Skip to content

Commit 2f269bd

Browse files
additional resilience
1 parent a8fb459 commit 2f269bd

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

tests/integration/workflow/test_workflow_execution.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
SUB_WF_1_NAME = 'complex_wf_signal_test_subworkflow_1'
2323
SUB_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+
2532
logger = 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+
181227
def generate_workflow(workflow_executor: WorkflowExecutor, workflow_name: str = WORKFLOW_NAME,
182228
task_name: str = TASK_NAME) -> ConductorWorkflow:
183229
return ConductorWorkflow(

0 commit comments

Comments
 (0)