Skip to content

feat(example): hello-cluster orchestrator — npm run hello-cluster (#1335)#1370

Merged
bokelley merged 1 commit into
mainfrom
bokelley/issue-1335
May 2, 2026
Merged

feat(example): hello-cluster orchestrator — npm run hello-cluster (#1335)#1370
bokelley merged 1 commit into
mainfrom
bokelley/issue-1335

Conversation

@bokelley

@bokelley bokelley commented May 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #1335. Unblocks the local test loop for #1066 (#1355).

Behavior

  • Boot: ~2s ready time for the current single-adapter set, well under the 5s budget.
  • Reap: SIGINT/SIGTERM → SIGTERM with 3s grace → SIGKILL. A tearingDown guard prevents N concurrent reap cycles when sibling exit handlers fire during the first reap.
  • Crash surfacing: ring buffer captures the last 10 lines of each child's stderr; replayed inline on health-fail and child-crash so adopters see WHY the child died (e.g. EADDRINUSE), not just TypeError: fetch failed.
  • Upstream preflight: each AdapterConfig declares its upstream env var + default URL + probe path. Cluster fetches every distinct upstream URL once with a 1.5s timeout BEFORE spawning. Network refusal → exit 1 with a copy-pasteable hint:
    signals: upstream not reachable at http://127.0.0.1:4150 (TypeError: fetch failed)
      — run 'npx @adcp/sdk@latest mock-server signal-marketplace --port 4150' first,
        or set UPSTREAM_URL to your real backend
    
    Hint suppresses the mock-server line when the user has explicitly overridden UPSTREAM_URL (they're clearly not running mock-server).
  • NODE_ENV: spawned children get NODE_ENV=development by default (the in-memory task registry refuses production). The cluster itself refuses to boot under a production parent unless HELLO_CLUSTER_I_KNOW_NOT_PROD=1 is set — defense in depth so an LLM scaffolding from this file or an adopter copy-pasting into staging can't accidentally rewrite NODE_ENV on a real deployment.
  • HELLO_CLUSTER_PORT_BASE=40000 shifts the whole range when 3001–3006 are busy or when running side-by-side clusters.
  • default_agent omission: when its target (sales) is in pending, the key is omitted with an explanatory YAML comment so storyboards expecting sales fail loud rather than silently retargeting to whichever adapter sorted first.

Deferred (filed-worthy follow-ups)

  • HELLO_CLUSTER_HOST for binding 0.0.0.0 (peer-container topologies)
  • HELLO_CLUSTER_STRICT=1 so CI fails when the expected adapter set isn't fully present
  • HELLO_CLUSTER_SKIP_PREFLIGHT=1 for offline boot

Review history

Two rounds of expert review (code-reviewer + adtech-product-expert + dx-expert in parallel). Round 1 surfaced: dead-code ternary, reap re-entrancy, missing child-stderr surfacing, NODE_ENV footgun, silent default_agent fallback, missing routing-key comment, missing structured pending:, missing upstream preflight. Round 2 verified those landed and surfaced: empty-string env edge case, AbortController timer leak, misleading mock-server hint when on a non-default backend, missing default_agent omission explainer. All now fixed.

Manifest shape verified end-to-end through the same yaml.parse + parsed.agents lookup pattern PR #1355's parseAgentsMapArgs uses.

Test plan

🤖 Generated with Claude Code

)

`examples/hello-cluster.ts` boots every per-specialism hello adapter on its
declared port (signals 3001 → retail-media 3006), preflights each adapter's
upstream backend, health-checks via MCP tools/list, and emits a YAML routing
manifest the storyboard runner (#1066, landing as #1355) consumes via
`--agents-map`.

Manifest shape locked end-to-end against #1355's parser: `agents.<key>.{ url,
auth }` matching `TestOptions['auth']`, top-level `default_agent`, plus a
top-level structured `pending: [...]` sibling that the runner ignores but
tooling can surface.

Today only the signals hello adapter exists; the rest (#1332/#1333/#1334
plus sales / retail-media) appear in the pending list and are picked up
automatically when their entrypoint files land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit f7741e5 into main May 2, 2026
10 of 11 checks passed
@bokelley bokelley deleted the bokelley/issue-1335 branch May 2, 2026 21:49
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.

Hello cluster orchestrator: boot N specialism adapters with one command

1 participant