77import logging
88from contextlib import asynccontextmanager
99from dataclasses import dataclass
10- from typing import AsyncIterator , Dict , Mapping , Optional , Sequence , Type
10+ from typing import AsyncIterator , Dict , Mapping , Optional , Sequence , Type , Union
1111
1212from typing_extensions import TypedDict
1313
1919import temporalio .runtime
2020import temporalio .workflow
2121
22+
2223from ..common import HeaderCodecBehavior
2324from ._interceptor import Interceptor
24- from ._worker import load_default_build_id
25+ from ._worker import load_default_build_id , WorkerConfig
26+ from temporalio .client import ClientConfig
2527from ._workflow import _WorkflowWorker
2628from ._workflow_instance import UnsandboxedWorkflowRunner , WorkflowRunner
2729from .workflow_sandbox import SandboxedWorkflowRunner
@@ -42,6 +44,7 @@ def __init__(
4244 namespace : str = "ReplayNamespace" ,
4345 data_converter : temporalio .converter .DataConverter = temporalio .converter .DataConverter .default ,
4446 interceptors : Sequence [Interceptor ] = [],
47+ plugins : Sequence [Union [temporalio .worker .Plugin , temporalio .client .Plugin ]] = [],
4548 build_id : Optional [str ] = None ,
4649 identity : Optional [str ] = None ,
4750 workflow_failure_exception_types : Sequence [Type [BaseException ]] = [],
@@ -62,8 +65,6 @@ def __init__(
6265 will be shared across all replay calls and never explicitly shut down.
6366 Users are encouraged to provide their own if needing more control.
6467 """
65- if not workflows :
66- raise ValueError ("At least one workflow must be specified" )
6768 self ._config = ReplayerConfig (
6869 workflows = list (workflows ),
6970 workflow_task_executor = (
@@ -82,6 +83,24 @@ def __init__(
8283 disable_safe_workflow_eviction = disable_safe_workflow_eviction ,
8384 header_codec_behavior = header_codec_behavior ,
8485 )
86+ root_worker_plugin : temporalio .worker .Plugin = temporalio .worker ._worker ._RootPlugin ()
87+ root_client_plugin : temporalio .client .Plugin = temporalio .client ._RootPlugin ()
88+ for plugin in reversed (plugins ):
89+ root_worker_plugin = plugin .init_worker_plugin (root_worker_plugin )
90+ root_client_plugin = plugin .init_client_plugin (root_client_plugin )
91+
92+ # Allow plugins to configure shared configurations with worker
93+ worker_config = WorkerConfig (** {k : v for k , v in self ._config .items () if k in WorkerConfig .__annotations__ })
94+ worker_config = root_worker_plugin .configure_worker (worker_config )
95+ self ._config .update ({k : v for k , v in worker_config .items () if k in ReplayerConfig .__annotations__ })
96+
97+ # Allow plugins to configure shared configurations with client
98+ client_config = ClientConfig (** {k : v for k , v in self ._config .items () if k in ClientConfig .__annotations__ })
99+ client_config = root_client_plugin .configure_client (client_config )
100+ self ._config .update ({k : v for k , v in client_config .items () if k in ReplayerConfig .__annotations__ })
101+
102+ if not self ._config ["workflows" ]:
103+ raise ValueError ("At least one workflow must be specified" )
85104
86105 def config (self ) -> ReplayerConfig :
87106 """Config, as a dictionary, used to create this replayer.
0 commit comments