5858 ChildWorkflowCancelled ,
5959 ChildWorkflowFailed ,
6060 ChildWorkflowTerminated ,
61+ DuplicateRegistrationError ,
6162 DurableOperationCancelled ,
6263 InvalidWorkflowDefinition ,
6364 NexusOperationFailed ,
@@ -124,6 +125,29 @@ def _validate_workflow_result(value: Any, cls: type) -> None:
124125 )
125126
126127
128+ def _workflow_handler_registries (
129+ cls : type ,
130+ ) -> tuple [dict [str , str ], dict [str , str ], dict [str , str ], dict [str , str ]]:
131+ handlers : dict [str , dict [str , str ]] = {kind : {} for kind in ("signal" , "query" , "update" , "update_validator" )}
132+ for attr in dir (cls ):
133+ if attr .startswith ("_" ):
134+ continue
135+ member = getattr (cls , attr , None )
136+ for kind , registry in handlers .items ():
137+ wire_name = getattr (member , f"__{ kind } _name__" , None )
138+ if not isinstance (wire_name , str ) or not wire_name :
139+ continue
140+ if kind == "signal" and wire_name == MESSAGE_STREAM_SIGNAL :
141+ raise ValueError (f"signal name { wire_name !r} is reserved by the workflow runtime" )
142+ if wire_name in registry :
143+ owner = f"{ cls .__module__ } .{ cls .__qualname__ } "
144+ raise DuplicateRegistrationError (
145+ kind , wire_name , f"{ owner } .{ registry [wire_name ]} " , f"{ owner } .{ attr } " ,
146+ )
147+ registry [wire_name ] = attr
148+ return handlers ["signal" ], handlers ["query" ], handlers ["update" ], handlers ["update_validator" ]
149+
150+
127151def defn (* , name : str ) -> Callable [[type [_WorkflowT ]], type [_WorkflowT ]]:
128152 """Register a class as a workflow type under a language-neutral name.
129153
@@ -136,28 +160,7 @@ def defn(*, name: str) -> Callable[[type[_WorkflowT]], type[_WorkflowT]]:
136160 def wrap (cls : type [_WorkflowT ]) -> type [_WorkflowT ]:
137161 cls .__workflow_name__ = name # type: ignore[attr-defined]
138162 _validate_workflow_entrypoint (cls )
139- signals : dict [str , str ] = {}
140- queries : dict [str , str ] = {}
141- updates : dict [str , str ] = {}
142- update_validators : dict [str , str ] = {}
143- for attr in dir (cls ):
144- if attr .startswith ("_" ):
145- continue
146- member = getattr (cls , attr , None )
147- signal_name = getattr (member , "__signal_name__" , None )
148- if isinstance (signal_name , str ) and signal_name :
149- if signal_name == MESSAGE_STREAM_SIGNAL :
150- raise ValueError (f"signal name { signal_name !r} is reserved by the workflow runtime" )
151- signals [signal_name ] = attr
152- query_name = getattr (member , "__query_name__" , None )
153- if isinstance (query_name , str ) and query_name :
154- queries [query_name ] = attr
155- update_name = getattr (member , "__update_name__" , None )
156- if isinstance (update_name , str ) and update_name :
157- updates [update_name ] = attr
158- update_validator_name = getattr (member , "__update_validator_name__" , None )
159- if isinstance (update_validator_name , str ) and update_validator_name :
160- update_validators [update_validator_name ] = attr
163+ signals , queries , updates , update_validators = _workflow_handler_registries (cls )
161164 cls .__workflow_signals__ = signals # type: ignore[attr-defined]
162165 cls .__workflow_queries__ = queries # type: ignore[attr-defined]
163166 cls .__workflow_updates__ = updates # type: ignore[attr-defined]
@@ -2578,9 +2581,12 @@ class Replayer:
25782581 def __init__ (self , * , workflows : Iterable [type ]) -> None :
25792582 self ._workflows : dict [str , type ] = {}
25802583 for workflow_cls in workflows :
2584+ _workflow_handler_registries (workflow_cls )
25812585 workflow_type = str (getattr (workflow_cls , "__workflow_name__" , workflow_cls .__name__ ))
25822586 if workflow_type in self ._workflows :
2583- raise ValueError (f"duplicate workflow type registered with Replayer: { workflow_type !r} " )
2587+ raise DuplicateRegistrationError (
2588+ "workflow" , workflow_type , self ._workflows [workflow_type ], workflow_cls ,
2589+ )
25842590 self ._workflows [workflow_type ] = workflow_cls
25852591 if not self ._workflows :
25862592 raise ValueError ("Replayer requires at least one workflow class" )
0 commit comments