@@ -125,6 +125,29 @@ def _validate_workflow_result(value: Any, cls: type) -> None:
125125 )
126126
127127
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+
128151def defn (* , name : str ) -> Callable [[type [_WorkflowT ]], type [_WorkflowT ]]:
129152 """Register a class as a workflow type under a language-neutral name.
130153
@@ -137,37 +160,7 @@ def defn(*, name: str) -> Callable[[type[_WorkflowT]], type[_WorkflowT]]:
137160 def wrap (cls : type [_WorkflowT ]) -> type [_WorkflowT ]:
138161 cls .__workflow_name__ = name # type: ignore[attr-defined]
139162 _validate_workflow_entrypoint (cls )
140- signals : dict [str , str ] = {}
141- queries : dict [str , str ] = {}
142- updates : dict [str , str ] = {}
143- update_validators : dict [str , str ] = {}
144-
145- def register_handler (kind : str , handlers : dict [str , str ], wire_name : str , attr : str ) -> None :
146- if wire_name in handlers :
147- owner = f"{ cls .__module__ } .{ cls .__qualname__ } "
148- raise DuplicateRegistrationError (
149- kind , wire_name , f"{ owner } .{ handlers [wire_name ]} " , f"{ owner } .{ attr } " ,
150- )
151- handlers [wire_name ] = attr
152-
153- for attr in dir (cls ):
154- if attr .startswith ("_" ):
155- continue
156- member = getattr (cls , attr , None )
157- signal_name = getattr (member , "__signal_name__" , None )
158- if isinstance (signal_name , str ) and signal_name :
159- if signal_name == MESSAGE_STREAM_SIGNAL :
160- raise ValueError (f"signal name { signal_name !r} is reserved by the workflow runtime" )
161- register_handler ("signal" , signals , signal_name , attr )
162- query_name = getattr (member , "__query_name__" , None )
163- if isinstance (query_name , str ) and query_name :
164- register_handler ("query" , queries , query_name , attr )
165- update_name = getattr (member , "__update_name__" , None )
166- if isinstance (update_name , str ) and update_name :
167- register_handler ("update" , updates , update_name , attr )
168- update_validator_name = getattr (member , "__update_validator_name__" , None )
169- if isinstance (update_validator_name , str ) and update_validator_name :
170- register_handler ("update_validator" , update_validators , update_validator_name , attr )
163+ signals , queries , updates , update_validators = _workflow_handler_registries (cls )
171164 cls .__workflow_signals__ = signals # type: ignore[attr-defined]
172165 cls .__workflow_queries__ = queries # type: ignore[attr-defined]
173166 cls .__workflow_updates__ = updates # type: ignore[attr-defined]
@@ -2588,6 +2581,7 @@ class Replayer:
25882581 def __init__ (self , * , workflows : Iterable [type ]) -> None :
25892582 self ._workflows : dict [str , type ] = {}
25902583 for workflow_cls in workflows :
2584+ _workflow_handler_registries (workflow_cls )
25912585 workflow_type = str (getattr (workflow_cls , "__workflow_name__" , workflow_cls .__name__ ))
25922586 if workflow_type in self ._workflows :
25932587 raise DuplicateRegistrationError (
0 commit comments