Skip to content

fix(scheduler): evict the old incarnation when a worker re-registers under a live id - #38

Open
b7r6 wants to merge 1 commit into
mainfrom
fix/worker-replacement-evicts
Open

b7r6 wants to merge 1 commit into
mainfrom
fix/worker-replacement-evicts

Conversation

@b7r6

@b7r6 b7r6 commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

What and why

Lane A stability fix from the findings catalog (see nativelink-findings-2026-10-05.csv
on the meta/findings-catalog-2026-10-05 branch), rebased onto OSS main
@bf4b3aa855. This fork PR exists to validate the change on CI that is
representative of upstream PR lanes (public read-only cache, same endpoints)
before any upstream submission.

How was this verified?

The branch carries its own regression tests (fails-without where the fix
class allows it — see the branch's test commits). This PR's purpose is the
full representative CI run; green here rehearses the exact checks an
upstream PR would face.

Risk

Fork-internal validation PR; nothing lands anywhere by merging this. The
underlying fix's risk assessment happens at upstream-submission time.

AI assistance

Agent-assisted pipeline (Claude) for rebase and PR mechanics under my
direction; the fix itself carries verification in its tests.

@github-actions

This comment has been minimized.

@b7r6
b7r6 force-pushed the fix/worker-replacement-evicts branch 2 times, most recently from 19056d6 to 46cd98b Compare October 7, 2026 20:28
…under a live id

ApiWorkerSchedulerImpl::add_worker used LruCache::put, which silently
replaced a live entry when a worker re-registered under an existing id.
The replaced Worker was dropped together with its running_action_infos:
nothing was requeued, the old channel never heard Disconnect, and the
gauges were only partially adjusted. Downstream, the replaced worker's
operations stayed Executing assigned to the id; when the new incarnation
was later evicted its empty list requeued nothing, and the eventual
timeout requeued the operation to another worker while the original
process might still be running it -- double execution.

Now ApiWorkerScheduler::add_worker treats a live entry under the same id
exactly like a disconnect before admitting the new incarnation: it goes
through immediate_evict_worker, which drains running_action_infos via
UpdateOperationType::UpdateWithDisconnect, sends Disconnect on the old
channel, and balances the connect/disconnect gauges. A requeue failure
is logged and does not block the reconnecting worker.

Deterministically reproduced by the DST fuzzer schedule in PR TraceMachina#2831;
the new regression test (worker re-registers mid-execution, asserts
Disconnect on the old channel, re-dispatch of the same operation to the
new channel, and completion) fails on unfixed main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@b7r6
b7r6 force-pushed the fix/worker-replacement-evicts branch from 46cd98b to a7a190d Compare October 8, 2026 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant