2222SUB_WF_1_NAME = 'complex_wf_signal_test_subworkflow_1'
2323SUB_WF_2_NAME = 'complex_wf_signal_test_subworkflow_2'
2424
25+ # Max time to wait for the batch of simple workflows to reach a terminal state.
26+ # These normally finish in seconds, but on a loaded shared server we've observed
27+ # them take ~30s+; the old ~12s budget (5s sleep + 1+2+4 retry backoff) produced
28+ # confirmed false-negative timeouts on workflows that did complete. Poll up to
29+ # this budget instead.
30+ WORKFLOW_COMPLETION_MAX_WAIT_SECONDS = 120
31+
2532logger = logging .getLogger (
2633 Configuration .get_logging_formatted_name (
2734 __name__
@@ -167,8 +174,14 @@ def scenario_workflow_execution(
167174 for i in range (workflow_quantity ):
168175 start_workflow_requests [i ] = StartWorkflowRequest (name = workflow_name )
169176 workflow_ids = workflow_executor .start_workflows (* start_workflow_requests )
177+ # Brief head start, then poll each workflow until it's terminal. The
178+ # workflows were all started together, so we share one wall-clock deadline
179+ # across the batch (bounding total wait to ~WORKFLOW_COMPLETION_MAX_WAIT_SECONDS
180+ # even on a genuine failure) rather than giving each its own long budget.
170181 sleep (workflow_completion_timeout )
182+ deadline = time .time () + WORKFLOW_COMPLETION_MAX_WAIT_SECONDS
171183 for workflow_id in workflow_ids :
184+ _wait_for_workflow_terminal (workflow_id , workflow_executor , deadline )
172185 _run_with_retry_attempt (
173186 validate_workflow_status ,
174187 {
@@ -178,6 +191,39 @@ def scenario_workflow_execution(
178191 )
179192
180193
194+ def _wait_for_workflow_terminal (workflow_id , workflow_executor , deadline ,
195+ poll_interval = 2 ):
196+ """Poll until the workflow reaches a terminal state or the shared deadline
197+ passes, logging progress (wf id + elapsed) so a slow-but-eventually-complete
198+ run is visible instead of surfacing as a bare timeout. A transient poll error
199+ is logged and retried. Returns the last observed status; the caller still
200+ runs validate_workflow_status for the actual assertion.
201+ """
202+ terminal = ('COMPLETED' , 'FAILED' , 'TIMED_OUT' , 'TERMINATED' )
203+ start = time .time ()
204+ status = None
205+ while True :
206+ try :
207+ workflow = workflow_executor .get_workflow (
208+ workflow_id = workflow_id , include_tasks = False )
209+ status = workflow .status
210+ except Exception as e : # transient blip against the shared server
211+ logger .warning ('error polling workflow %s (%.0fs elapsed): %s' ,
212+ workflow_id , time .time () - start , e )
213+ if status in terminal :
214+ logger .info ('workflow %s reached %s after %.0fs' ,
215+ workflow_id , status , time .time () - start )
216+ return status
217+ if time .time () >= deadline :
218+ logger .warning (
219+ 'workflow %s still %s after %.0fs; giving up wait' ,
220+ workflow_id , status , time .time () - start )
221+ return status
222+ logger .info ('workflow %s still %s after %.0fs; waiting' ,
223+ workflow_id , status , time .time () - start )
224+ sleep (poll_interval )
225+
226+
181227def generate_workflow (workflow_executor : WorkflowExecutor , workflow_name : str = WORKFLOW_NAME ,
182228 task_name : str = TASK_NAME ) -> ConductorWorkflow :
183229 return ConductorWorkflow (
0 commit comments