Skip to content

Commit cce3126

Browse files
additional test diagnostic output
1 parent dc14a29 commit cce3126

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

tests/integration/test_comprehensive_e2e.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ def failing_task(should_fail: bool) -> dict:
121121
# Main test class
122122
class TestComprehensiveE2E(unittest.TestCase):
123123

124+
# Annotated workers this suite relies on. Every one must be discovered by
125+
# the scan AND have a live process, otherwise its task silently stays
126+
# SCHEDULED forever (which is exactly how a non-starting task_in_progress
127+
# worker manifested as a "4 != 5 tasks" failure in CI).
128+
EXPECTED_WORKERS = (
129+
'sync_basic',
130+
'async_basic',
131+
'complex_schema',
132+
'task_in_progress',
133+
'failing_task',
134+
)
135+
124136
@classmethod
125137
def setUpClass(cls):
126138
from tests.integration.conftest import skip_if_server_unavailable
@@ -191,12 +203,55 @@ def test_02_start_workers(self):
191203
self.__class__.task_handler = handler
192204
time.sleep(5) # Wait for startup
193205

206+
# Confirm every expected annotated worker was discovered by the scan AND
207+
# its child process is actually alive. Assert each one individually so a
208+
# failure names the exact worker that didn't come up, instead of the
209+
# failure surfacing later (and opaquely) as a task stuck in SCHEDULED.
210+
started = {}
211+
for worker, process in zip(handler.workers, handler.task_runner_processes):
212+
started[worker.get_task_definition_name()] = process.is_alive()
213+
print(f"Discovered {len(started)} annotated worker(s): {sorted(started)}")
214+
215+
for name in self.EXPECTED_WORKERS:
216+
self.assertIn(
217+
name, started,
218+
f"worker '{name}' was not discovered by the annotated-worker scan; "
219+
f"discovered={sorted(started)}")
220+
self.assertTrue(
221+
started[name],
222+
f"worker '{name}' was discovered but its process is not alive")
223+
194224
print("✓ Workers started")
195225
self.__class__.workers_started = True
196226
self.assertTrue(self.workers_started)
197227

198228
EXPECTED_TASK_COUNT = 5
199229

230+
def _dump_stuck_task_diagnostics(self, wf):
231+
"""When a run fails to complete, print server-side poll data and queue
232+
sizes so CI shows *why* a task is stuck (e.g. no worker polling its
233+
queue) rather than just a bare task-count assertion. Poll data is
234+
server-side, so it survives regardless of worker child-process log
235+
capture.
236+
"""
237+
from conductor.client.orkes.orkes_task_client import OrkesTaskClient
238+
task_client = OrkesTaskClient(self.config)
239+
240+
stuck = [t.task_def_name for t in (getattr(wf, 'tasks', None) or [])
241+
if t.status not in ('COMPLETED', 'FAILED', 'FAILED_WITH_TERMINAL_ERROR')]
242+
print(f" [diag] non-terminal tasks: {stuck}")
243+
244+
# Include the expected workers so we can compare a stuck queue against a
245+
# known-good one (e.g. task_in_progress vs sync_basic).
246+
for task_type in sorted(set(stuck) | set(self.EXPECTED_WORKERS)):
247+
try:
248+
queue_size = task_client.get_queue_size_for_task(task_type)
249+
poll_data = task_client.get_task_poll_data(task_type) or []
250+
pollers = [(p.worker_id, p.domain, p.last_poll_time) for p in poll_data]
251+
print(f" [diag] {task_type}: queue_size={queue_size} pollers={pollers}")
252+
except Exception as e: # diagnostics must never mask the real failure
253+
print(f" [diag] {task_type}: failed to fetch poll data: {e!r}")
254+
200255
def _run_workflow_to_terminal(self, workflow_client, timeout_s=90):
201256
"""Start the e2e workflow and wait until it is genuinely terminal with
202257
all expected tasks present. Returns (wf_id, workflow_or_None). A None
@@ -247,6 +302,7 @@ def test_03_execute_workflow(self):
247302
print(f"attempt {attempt + 1}: wf={wf_id} "
248303
f"status={getattr(wf, 'status', None)} "
249304
f"tasks={len(getattr(wf, 'tasks', []) or [])}; retrying")
305+
self._dump_stuck_task_diagnostics(wf)
250306

251307
# Assertions
252308
self.assertIsNotNone(

0 commit comments

Comments
 (0)