Skip to content

Commit 0bbf504

Browse files
author
Alex Wang
committed
test(insight): harden worker lifecycle checks
Make the two shared-timeout tests wait deterministically for their released lane workers to stop before returning, so their daemon workers cannot exit between a later test's baseline capture and its assertion. Replace the fragile process-global thread-count delta in test_blocked_worker_is_not_replaced with lane-local worker identity, aliveness, and a lane-scoped worker count. This proves the blocked lane never spawns a replacement without depending on global thread state. Product code is unchanged.
1 parent 50a0ad5 commit 0bbf504

1 file changed

Lines changed: 29 additions & 2 deletions

File tree

packages/aws-durable-execution-sdk-python-insight/tests/test_export_scheduler.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ def _insight_thread_count() -> int:
4646
)
4747

4848

49+
def _lane_worker_count(lane) -> int:
50+
"""Count live worker threads that belong to *this* lane by identity.
51+
52+
Each lane names its worker ``workflow-insight-export-{id(lane)}``, so this is
53+
scoped to the given lane and is unaffected by daemon workers other tests may
54+
still be winding down -- unlike a process-global thread-count delta.
55+
"""
56+
name = f"workflow-insight-export-{id(lane)}"
57+
return sum(1 for t in threading.enumerate() if t.name == name and t.is_alive())
58+
59+
4960
class RecordingExporter:
5061
"""Records every export/flush in call order (fast, non-blocking)."""
5162

@@ -350,6 +361,7 @@ def test_export_and_flush_exceptions_are_isolated():
350361
def test_shared_timeout_bounds_invocation_end_delay():
351362
exporter = BlockingExporter()
352363
scheduler = _ExportScheduler([exporter])
364+
lane = scheduler._lanes[0]
353365
scheduler.schedule(ARN_A, _rec(ARN_A, "a1"))
354366
assert _wait_until(exporter.started.is_set)
355367
start = time.monotonic()
@@ -358,6 +370,9 @@ def test_shared_timeout_bounds_invocation_end_delay():
358370
assert ok is False # degraded to best-effort
359371
assert elapsed < 2.0 # bounded by the shared deadline, not the blocked export
360372
exporter.release() # let the daemon drain and exit
373+
# Wait for the released worker to actually stop so it cannot leak into a
374+
# later test's baseline thread count.
375+
assert _wait_until(lambda: not lane._worker_alive())
361376

362377

363378
def test_shared_timeout_across_multiple_lanes_is_not_additive():
@@ -373,26 +388,38 @@ def test_shared_timeout_across_multiple_lanes_is_not_additive():
373388
assert elapsed < 0.9
374389
e1.release()
375390
e2.release()
391+
# Wait for both released workers to actually stop so neither leaks into a
392+
# later test's baseline thread count.
393+
assert _wait_until(
394+
lambda: not any(lane._worker_alive() for lane in scheduler._lanes)
395+
)
376396

377397

378398
# -- worker lifecycle ---------------------------------------------------------
379399

380400

381401
def test_blocked_worker_is_not_replaced():
382-
base = _insight_thread_count()
383402
exporter = BlockingExporter()
384403
scheduler = _ExportScheduler([exporter])
385404
lane = scheduler._lanes[0]
386405
scheduler.schedule(ARN_A, _rec(ARN_A, "a1"))
387406
assert _wait_until(exporter.started.is_set)
388407
worker = lane._worker
408+
assert worker is not None and worker.is_alive()
409+
# The blocked lane already has exactly one live worker of its own.
410+
assert _lane_worker_count(lane) == 1
389411
# More scheduling and an invocation-end (which enqueues a flush + requests
390412
# stop) must not spawn a replacement while the worker is blocked.
391413
scheduler.schedule(ARN_A, _rec(ARN_A, "a2"))
392414
scheduler.schedule(ARN_B, _rec(ARN_B, "b1"))
393415
scheduler.end_invocation(0.1)
416+
# Identity: the lane still holds the SAME blocked worker -- no replacement
417+
# thread was swapped in -- and it is still the only live worker for this
418+
# lane. Both checks are scoped to this lane, so they cannot flake on daemon
419+
# workers other tests are winding down.
394420
assert lane._worker is worker
395-
assert _insight_thread_count() - base == 1
421+
assert worker.is_alive()
422+
assert _lane_worker_count(lane) == 1
396423
exporter.release()
397424

398425

0 commit comments

Comments
 (0)