Skip to content

Make the A2A task store per-server-instance and bounded#2

Merged
dubh3124 merged 1 commit into
dubh3124:mainfrom
daryllundy:fix/a2a-task-store-isolation
Jun 26, 2026
Merged

Make the A2A task store per-server-instance and bounded#2
dubh3124 merged 1 commit into
dubh3124:mainfrom
daryllundy:fix/a2a-task-store-isolation

Conversation

@daryllundy

@daryllundy daryllundy commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #1.

Problem

The A2A server kept its task registry in a module-scope Map
(src/a2a/server.ts), so all createDirectorA2AServer instances in a process
shared it — ListTasks on one server returned another server's tasks, and the
map was never pruned (unbounded growth on a long-running server).

Change

  • Move the Map into each createDirectorA2AServer instance; thread it
    explicitly through handleJsonRpc and createAndRunTask, matching the
    existing pattern for dependencies.
  • Add a MAX_TASKS = 1000 cap with oldest-first eviction (Map insertion order)
    so the store can't grow without bound.
  • Add a regression test: two servers each get their own store; a task sent to
    server A is not visible from server B.

No changes to JSON-RPC method names, A2ATask/artifact shapes, or any SDK file.
A2A stays a thin adapter over the SDK.

Note on scope (happy to adjust)

The isolation fix is the core of this PR. The eviction cap is an
optional add-on — it changes one observable behavior (GetTask on a very old,
evicted id returns "not found" on a busy server). If you'd prefer the minimal
isolation-only change, or a different cap / configurable limit, say the word and
I'll trim it.

Testing

  • npm run typecheck — passes
  • npm test — passes (16 tests incl. the new isolation test)
  • npm run build — passes
  • npm audit --audit-level=moderate — 0 vulnerabilities
  • npm run pack:dry — unaffected (change is src/-only)

Disclosure

I used Claude Code (Anthropic's agentic coding tool) to identify and implement
this fix. I reviewed the diff and ran the full check suite locally. The commit
carries a Co-Authored-By trailer for that assistance.

Move the task Map from module scope into each createDirectorA2AServer call
so server instances no longer share one global registry (ListTasks on one
instance previously returned another instance's tasks). Add a MAX_TASKS=1000
cap with oldest-first eviction so a long-running server's store cannot grow
unbounded. Thread the store explicitly through handleJsonRpc and
createAndRunTask, matching how dependencies are already passed. Add an
isolation test verifying two servers do not share tasks.

Found and fixed with assistance from Claude Code (Anthropic).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dubh3124 dubh3124 merged commit affcf2d into dubh3124:main Jun 26, 2026
2 checks passed
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.

createDirectorA2AServer() uses a module-scoped task Map, causing cross-instance leakage and unbounded growth

2 participants