fix(pyamber): wait out a pause before completing the worker - #7624
fix(pyamber): wait out a pause before completing the worker#7624aglinxinyuan wants to merge 1 commit into
Conversation
Backport auto-label reportThis
|
Automated Reviewer SuggestionsBased on the
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7624 +/- ##
=========================================
Coverage 88.99% 88.99%
Complexity 4348 4348
=========================================
Files 1178 1178
Lines 46836 46838 +2
Branches 5226 5226
=========================================
+ Hits 41681 41683 +2
Misses 3416 3416
Partials 1739 1739
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 436 | 0.266 | 22,162/28,905/28,905 us | 🔴 +8.8% / 🔴 +77.2% |
| 🔴 | bs=100 sw=10 sl=64 | 891 | 0.544 | 109,553/152,198/152,198 us | 🔴 +12.8% / 🔴 +40.7% |
| 🔴 | bs=1000 sw=10 sl=64 | 1,098 | 0.67 | 911,194/1,003,346/1,003,346 us | 🔴 +5.2% / 🟢 -8.5% |
Baseline details
Latest main 310ab88 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 436 tuples/sec | 453 tuples/sec | 775.33 tuples/sec | -3.8% | -43.8% |
| bs=10 sw=10 sl=64 | MB/s | 0.266 MB/s | 0.276 MB/s | 0.473 MB/s | -3.6% | -43.8% |
| bs=10 sw=10 sl=64 | p50 | 22,162 us | 20,377 us | 12,743 us | +8.8% | +73.9% |
| bs=10 sw=10 sl=64 | p95 | 28,905 us | 31,124 us | 16,310 us | -7.1% | +77.2% |
| bs=10 sw=10 sl=64 | p99 | 28,905 us | 31,124 us | 18,926 us | -7.1% | +52.7% |
| bs=100 sw=10 sl=64 | throughput | 891 tuples/sec | 921 tuples/sec | 1,001 tuples/sec | -3.3% | -11.0% |
| bs=100 sw=10 sl=64 | MB/s | 0.544 MB/s | 0.562 MB/s | 0.611 MB/s | -3.2% | -10.9% |
| bs=100 sw=10 sl=64 | p50 | 109,553 us | 107,259 us | 101,399 us | +2.1% | +8.0% |
| bs=100 sw=10 sl=64 | p95 | 152,198 us | 134,890 us | 108,206 us | +12.8% | +40.7% |
| bs=100 sw=10 sl=64 | p99 | 152,198 us | 134,890 us | 118,195 us | +12.8% | +28.8% |
| bs=1000 sw=10 sl=64 | throughput | 1,098 tuples/sec | 1,108 tuples/sec | 1,026 tuples/sec | -0.9% | +7.0% |
| bs=1000 sw=10 sl=64 | MB/s | 0.67 MB/s | 0.677 MB/s | 0.626 MB/s | -1.0% | +7.0% |
| bs=1000 sw=10 sl=64 | p50 | 911,194 us | 899,001 us | 996,304 us | +1.4% | -8.5% |
| bs=1000 sw=10 sl=64 | p95 | 1,003,346 us | 953,842 us | 1,042,531 us | +5.2% | -3.8% |
| bs=1000 sw=10 sl=64 | p99 | 1,003,346 us | 953,842 us | 1,074,934 us | +5.2% | -6.7% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,458.34,200,128000,436,0.266,22162.09,28905.47,28905.47
1,100,10,64,20,2245.35,2000,1280000,891,0.544,109552.70,152198.16,152198.16
2,1000,10,64,20,18217.01,20000,12800000,1098,0.670,911194.07,1003345.94,1003345.94
What changes were proposed in this PR?
Root cause.
MainLoop._process_end_channelends withself.complete(), which transits the worker toCOMPLETED. Nothing between that call and the last control check above it drains control, but the coordinator pauses on its own schedule — so aPauseWorkercommand can land in that window and leave the workerPAUSED.PAUSED -> COMPLETEDis forbidden by the transition graph, sotransit_toraisedInvalidTransitionException, which killed the main loop thread:The worker now waits the pause out before completing, which is what the Scala runtime already does:
DPThread's input selection only picks control channels whilepauseManager.isPaused, so a paused Scala worker never advances to completion.The wait is guarded on
pause_manager.is_paused()rather than draining control unconditionally._check_and_process_controlblocks while the data lane is disabled, and backpressure disables that lane too (DisableType.DISABLE_BY_BACKPRESSURE) — an unguarded drain here would park a worker that is merely backpressured. Guarded, the happy path is untouched: not paused, loop body never runs.Deliberately not changed: the transition graph. Adding
PAUSED -> COMPLETEDwould be the smaller diff, butWORKER_STATE_TRANSITIONSmirrors Scala'sWorkerStateManager(PAUSED -> Set(RUNNING)) by contract, and the two must agree.Any related issues, documentation, discussions?
Closes #5913
How was this PR tested?
New regression test, written first and confirmed to fail red against unmodified source with the exact production traceback (
Cannot transit from PAUSED to COMPLETEDat_process_end_channel->complete()).test_pause_landing_before_completion_defers_it_until_resumemakes the race deterministic by pausing insideall_ports_completed()— the last call beforecomplete(), with no control check in between, i.e. exactly the production window. It pins both directions:PAUSED, and noWorkerExecutionCompletedis announced;Resume: the worker reachesCOMPLETEDand announces it.From
amber/:python -m pytest src/test/python/core/runnables/test_main_loop.py— 35 passed (34 pre-existing + the new one).ruff check src/main/python src/test/python && ruff format --check src/main/python src/test/python— clean.Pre-existing local failures in
test_iceberg_document.py,test_tuple.py::test_hashandtest_expression_evaluator.pywere confirmed identical with this change stashed, so they are unrelated to it.Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5)