a2aproject / a2aproject/a2a-dotnet
Task live coordination is process-local across server instances
- 主要言語
- C#
- スター
- 262
- フォーク
- 64
- 平均マージ
- 5日 2時間
- マージ済み PR(30日)
- 31
説明
## Summary
Task persistence can be shared across server instances, but two live coordination paths in `A2AServer` are process-local:
- `SubscribeToTask` uses `ChannelEventNotifier` subscriber channels.
- `CancelTask` looks up the running task in `_backgroundCancellations`, an in-process dictionary of `CancellationTokenSource` instances.
Consequently, a request routed to a different process/pod can read and mutate the durable task while failing to notify the subscriber or interrupt the process that is executing the task.
This is not a task snapshot persistence issue. `GetTask` may return the correct durable state while live delivery or execution interruption has not occurred.
## Current behavior
### Subscribe across instances
From [`ChannelEventNotifier`](https://github.com/a2aproject/a2a-dotnet/blob/87fd44843dd16339cdb59c2ff547fe374ac46736/src/A2A/Server/ChannelEventNotifier.cs), subscribers and per-task locks are stored in process memory.
1. Pod B accepts `SubscribeToTask` and creates a local subscriber channel.
2. Pod A applies and persists a later task event.
3. Pod A notifies only subscribers registered in Pod A.
4. The subscriber on Pod B can miss the live event even though `GetTask` later returns the updated snapshot.
### Cancel across instances
In [`A2AServer.CancelTaskAsync`](https://github.com/a2aproject/a2a-dotnet/blob/fdf22d790cc3c80a157311c41d2ec0cd71815173/src/A2A/Server/A2AServer.cs#L822-L863), background execution cancellation uses `_backgroundCancellations.TryRemove(request.Id, ...)`.
1. Pod A owns a return-immediately background execution and its local cancellation token.
2. Pod B accepts `CancelTask` for the same durably stored task.
3. Pod B has no matching entry in its `_backgroundCancellations` dictionary.
4. The task may be projected or persisted as canceled by the handler/store while the actual work on Pod A continues consuming resources.
Application-level fencing can reject stale terminal writes, but it does not stop the running work.
## Expected behavior
For multi-instance deployments, the SDK should expose an explicit live-coordination extension point or clearly document that the default implementation requires routing affinity/single-instance hosting.
A robust application-provided implementation should be able to use:
- durable task state/events as the authority;
- a distributed notifier/backplane as a low-latency wake-up hint;
- durable replay or polling as a fallback for lost notifications;
- separate notification semantics for subscriber wake-up and execution cancellation.
The notifier must not become the source of truth, and duplicate, delayed, reordered, or lost notifications must be safe.
## Possible SDK directions
- Document that `ChannelEventNotifier` and `_backgroundCancellations` are process-local.
- Expose injectable abstractions for subscription notification and active-execution cancellation/routing while retaining the current in-memory defaults.
- Keep persistence (`ITaskStore`) separate from notification, but document how a distributed store and distributed coordination provider compose.
- Add deterministic two-server tests demonstrating the default limitation and validating custom distributed implementations.
## Minimal repros
### Subscribe
1. Register a subscriber for `taskId` on notifier/server A.
2. Apply or notify an event on notifier/server B.
3. Observe that A's subscriber does not receive it.
4. Repeat with one notifier and observe successful delivery.
### Cancel
1. Start return-immediately work for `taskId` on server A.
2. Share the task snapshot through a common `ITaskStore`.
3. Call `CancelTaskAsync` on server B.
4. Observe that server A's cancellation token is not canceled.
5. Repeat on server A and observe that local cancellation succeeds.
## Why this matters
A service can pass single-process tests and expose correct durable snapshots while still hanging subscriptions or continuing canceled work under load-balanced production routing. The topology limitation should be explicit, and applications need supported extension seams to provide cross-instance coordination.
コントリビューションガイド
評価
この issue はまだ評価されていません。