Commit 23d9086
fix(af run): eliminate port race that killed healthy nodes on startup (#737)
`af run <node>` intermittently failed with 'agent node did not become ready
within 10s' — worst for import-heavy nodes like pr-af. Root cause is a
check-then-exec race between the runner and the SDK:
1. The runner probes a free port, releases the probe, exports PORT=N, then
polls ONLY port N for readiness.
2. If N is momentarily unavailable when the child binds, the SDK SILENTLY
moves to the next free port (N+1) — a port the runner never learns about.
The runner then polls the dead port N until timeout and kills a node that
actually came up fine on N+1.
3. The 10s readiness window is also too short for nodes with large import
graphs, independent of the race.
Fix (regression-safe, gated):
- Runner exports AGENTFIELD_STRICT_PORT=1 alongside PORT.
- SDK, only when that signal is set, binds the injected PORT authoritatively:
if it is unavailable it exits with a clear error instead of silently
bumping, so the runner and node can never disagree about the port. Absent
the signal (standalone `python -m <node>.app`, manual PORT=...), the old
lenient auto-bump behavior is unchanged — no regression.
- Readiness timeout is now 30s and configurable via
AGENTFIELD_NODE_READY_TIMEOUT (whole seconds).
- Guard PortManager's reserved-ports map with a mutex (it was read/written
without synchronization).
Verified: with the patched control plane + SDK, all four reference nodes
(swe-planner, cloudsecurity-af, sec-af, pr-af) start on their assigned ports
and pass health; pr-af — previously failing almost every run — now binds its
assigned port every time.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent e816e3f commit 23d9086
3 files changed
Lines changed: 50 additions & 5 deletions
File tree
- control-plane/internal
- core/services
- infrastructure/process
- sdk/python/agentfield
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| |||
120 | 121 | | |
121 | 122 | | |
122 | 123 | | |
123 | | - | |
| 124 | + | |
124 | 125 | | |
125 | 126 | | |
126 | 127 | | |
| |||
513 | 514 | | |
514 | 515 | | |
515 | 516 | | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
516 | 522 | | |
517 | 523 | | |
518 | 524 | | |
| |||
616 | 622 | | |
617 | 623 | | |
618 | 624 | | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
619 | 639 | | |
620 | 640 | | |
621 | 641 | | |
| |||
Lines changed: 9 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| |||
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
29 | | - | |
30 | | - | |
| 31 | + | |
| 32 | + | |
31 | 33 | | |
32 | | - | |
| 34 | + | |
33 | 35 | | |
34 | 36 | | |
35 | 37 | | |
| |||
53 | 55 | | |
54 | 56 | | |
55 | 57 | | |
| 58 | + | |
| 59 | + | |
56 | 60 | | |
57 | 61 | | |
58 | 62 | | |
| |||
67 | 71 | | |
68 | 72 | | |
69 | 73 | | |
| 74 | + | |
| 75 | + | |
70 | 76 | | |
71 | 77 | | |
72 | 78 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
677 | 677 | | |
678 | 678 | | |
679 | 679 | | |
680 | | - | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
681 | 700 | | |
682 | 701 | | |
683 | 702 | | |
| |||
0 commit comments