fix(amber): treat a queued coordinator reply as processed work in EndWorker#6916
Open
aglinxinyuan wants to merge 3 commits into
Open
fix(amber): treat a queued coordinator reply as processed work in EndWorker#6916aglinxinyuan wants to merge 3 commits into
aglinxinyuan wants to merge 3 commits into
Conversation
…Worker On every normal region termination the coordinator sends EndWorker from inside the portCompleted handler, so the ReturnInvocation replying to that same portCompleted is emitted afterwards on the same FIFO control channel and legitimately sits behind EndWorker in the worker's arrival queue. EndHandler treated any queued element as unprocessed work and failed the first termination attempt, producing 2 ERRORs + 2 WARNs + 2 stack traces per teardown before the 200 ms retry succeeded. A ReturnInvocation is not work: processing it only fulfills a promise for a request the worker already issued, and every worker-to-coordinator call discards its future. Both workers now exclude queued ReturnInvocations from the unprocessed-messages check; everything else (control invocations, data, timer-based controls, actor commands) still blocks termination. The Python handler additionally called input_queue.get() inside its warning f-string - a destructive dequeue that silently dropped the queued message - and then bare-asserted, shipping a blank ControlError. It now uses a non-destructive peek() and a reply-aware work counter, and raises with the same message string as the Scala side. Also demotes the detail-free duplicate WARN in RegionExecutionManager (terminateWorkersWithRetry logs the same failure with attempt context) and fixes the false doc claim that EndWorker is the last message a worker receives. Retry semantics are unchanged: RegionExecutionManagerSpec and WorkflowExecutionManagerSpec pass untouched.
Contributor
Automated Reviewer SuggestionsBased on the
|
This was referenced Jul 27, 2026
Open
…0fd2ec # Conflicts: # amber/src/main/python/core/architecture/handlers/control/end_worker_handler.py # amber/src/test/python/core/architecture/handlers/control/test_end_worker_handler.py
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6916 +/- ##
=========================================
Coverage 78.95% 78.95%
- Complexity 3795 3801 +6
=========================================
Files 1161 1161
Lines 46084 46114 +30
Branches 5110 5117 +7
=========================================
+ Hits 36384 36410 +26
- Misses 8077 8079 +2
- Partials 1623 1625 +2
*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:
|
Contributor
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🟢 | bs=10 sw=10 sl=64 | 402 | 0.245 | 23,911/34,743/34,743 us | 🟢 -12.9% / 🔴 +112.2% |
| 🔴 | bs=100 sw=10 sl=64 | 792 | 0.483 | 125,006/149,286/149,286 us | 🔴 +5.2% / 🔴 +36.6% |
| 🟢 | bs=1000 sw=10 sl=64 | 913 | 0.557 | 1,092,965/1,135,757/1,135,757 us | 🟢 -5.1% / 🔴 -8.6% |
Baseline details
Latest main 49f9e2c from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 402 tuples/sec | 369 tuples/sec | 759.72 tuples/sec | +8.9% | -47.1% |
| bs=10 sw=10 sl=64 | MB/s | 0.245 MB/s | 0.225 MB/s | 0.464 MB/s | +8.9% | -47.2% |
| bs=10 sw=10 sl=64 | p50 | 23,911 us | 27,465 us | 12,653 us | -12.9% | +89.0% |
| bs=10 sw=10 sl=64 | p95 | 34,743 us | 39,396 us | 16,371 us | -11.8% | +112.2% |
| bs=10 sw=10 sl=64 | p99 | 34,743 us | 39,396 us | 19,941 us | -11.8% | +74.2% |
| bs=100 sw=10 sl=64 | throughput | 792 tuples/sec | 826 tuples/sec | 966.78 tuples/sec | -4.1% | -18.1% |
| bs=100 sw=10 sl=64 | MB/s | 0.483 MB/s | 0.504 MB/s | 0.59 MB/s | -4.2% | -18.1% |
| bs=100 sw=10 sl=64 | p50 | 125,006 us | 118,861 us | 103,654 us | +5.2% | +20.6% |
| bs=100 sw=10 sl=64 | p95 | 149,286 us | 155,008 us | 109,308 us | -3.7% | +36.6% |
| bs=100 sw=10 sl=64 | p99 | 149,286 us | 155,008 us | 116,369 us | -3.7% | +28.3% |
| bs=1000 sw=10 sl=64 | throughput | 913 tuples/sec | 914 tuples/sec | 997.95 tuples/sec | -0.1% | -8.5% |
| bs=1000 sw=10 sl=64 | MB/s | 0.557 MB/s | 0.558 MB/s | 0.609 MB/s | -0.2% | -8.6% |
| bs=1000 sw=10 sl=64 | p50 | 1,092,965 us | 1,087,281 us | 1,007,348 us | +0.5% | +8.5% |
| bs=1000 sw=10 sl=64 | p95 | 1,135,757 us | 1,196,827 us | 1,050,149 us | -5.1% | +8.2% |
| bs=1000 sw=10 sl=64 | p99 | 1,135,757 us | 1,196,827 us | 1,079,497 us | -5.1% | +5.2% |
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,497.68,200,128000,402,0.245,23911.47,34743.20,34743.20
1,100,10,64,20,2526.29,2000,1280000,792,0.483,125006.10,149285.52,149285.52
2,1000,10,64,20,21912.34,20000,12800000,913,0.557,1092964.81,1135757.19,1135757.19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this PR?
Root cause. On every normal region termination, the coordinator sends
EndWorkerfrom inside theportCompletedhandler, so theReturnInvocationreplying to that sameportCompletedis always emitted afterEndWorkeron the same FIFO control channel:Whether the trailing reply has landed when
EndHandlerruns is a thread-scheduling race, so healthy teardowns routinely fail the first termination attempt and log an alarming storm (2 ERRORs + 2 WARNs + 2 stack traces, then a wasted 200 ms retry). A queuedReturnInvocationis not work: processing it only fulfills a promise for a request the worker already issued, and every worker-to-coordinator call discards its future (DataProcessor.scala:179,187,224,312), so no continuation can be lost.Fix. Both workers now exclude queued
ReturnInvocations from the unprocessed-messages check. Everything that is work —ControlInvocations, data, ECMs, timer-based controls, actor commands — still blocks termination, and the 150 × 200 ms retry/give-up contract is untouched.EndWorkerattemptEndWorker(since #6522; before that it was silently dropped by a destructiveget())Changes:
EndHandler.scala: scan the arrival queue for pending work instead of testing bare emptiness; the warning names the payload type and channel instead of dumping the element; scaladoc no longer claimsEndWorkeris the last message a worker receives.end_worker_handler.py/internal_queue.py: reply-awarehas_unprocessed_work()(anAtomicIntegerwork counter maintained input/get, since the multi-queue offers no iteration; it also sees work in paused/backpressured sub-queues thatsize()/get()hide) plus a non-destructiveInternalQueue.peek()used for the failure diagnostic. This builds on fix(pyamber): stop EndWorker from consuming straggler messages #6522, which stopped the handler from consuming stragglers; after this PR the Python worker also stops failing on the benign trailing reply, keeping it at parity with the Scala side (same"worker still has unprocessed messages"failure string).RegionExecutionManager.scala: fixed the false doc ("This will be the last message each worker receives") and demoted the detail-free duplicate"Error when terminating region X."WARN to debug —terminateWorkersWithRetrylogs the same failure with attempt context (WARN) or gives up loudly (ERROR), unchanged.Any related issues, documentation, discussions?
Related: #6796 — this addresses the
EndWorkerretry-storm item behaviorally (the expected race no longer fails the first attempt) rather than by adjusting log levels. Follow-up to the CI log-verbosity work in #6797 and to #6522 (Python straggler-consumption fix). Adjacent teardown defects found during this investigation are filed separately: #6918, #6919, #6920, #6921, #6922, #6923, #6924, #6925.How was this PR tested?
EndHandlerSpec(the three pre-existing tests are untouched — control invocations and actor commands still failendWorker): new regression tests for the exact CI payload (ReturnInvocation(2, EmptyReturn())queued → success), multiple queued replies, aControlInvocationqueued behind a reply (the scan must not stop at the head), and queue-size preservation on both paths. Written test-first: the two new success tests fail without theEndHandlerchange.test_end_worker_handler.py: keeps the five tests introduced by fix(pyamber): stop EndWorker from consuming straggler messages #6522 verbatim (their straggler elements still count as work) and adds the reply-aware cases — a queued coordinator reply succeeds and stays queued (size() == 1afterwards), aControlInvocationbehind a reply still fails, queued data still fails, and repeated calls are idempotent across coordinator retries.test_internal_queue.py:peek()(None on empty, non-destructive) andhas_unprocessed_work()(ignores replies; counts invocations, data, ECMs, SYSTEM items; sees data in a disabled sub-queue; not counted for rejected elements).RegionExecutionManagerSpec,WorkflowExecutionManagerSpec,DPThreadSpec,WorkerSpec,AsyncRPCClientSpec.scalafmtCheck,scalafixAll --check,ruff check+ruff format --checkall pass.Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Fable 5)