a2aproject / a2aproject/a2a-dotnet

Task live coordination is process-local across server instances

オープン
#463 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
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 はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。