a2aproject / a2aproject/a2a-python

[Feat]: NoSQL (MongoDB) TaskStore / PushNotificationConfigStore backend — production-verified reference implementation available

Đang mở
#1,210 2 bình luận 0 reaction 1 người được giao Được @ishymko nhận Xem trên GitHub
component: server status: needs review
Ngôn ngữ chính
Python
Star
2.1k
Fork
496
Merge trung bình
4 ngày 17 giờ
Pull request đã merge (30 ngày)
12

Mô tả

## Summary

The SDK currently ships two `TaskStore` backends: `InMemoryTaskStore` and the SQLAlchemy-based `DatabaseTaskStore` (`a2a-sdk[sql]`). There is no supported path for document/NoSQL databases, even though task records are a natural fit for them. We built and deployed a MongoDB-backed `TaskStore` + `PushNotificationConfigStore` for a production A2A server (FastAPI, multi-replica) and would like to propose upstreaming a generic version — either as an optional extra (e.g. `a2a-sdk[mongodb]`) or as a documented reference implementation.

## Why a document store fits this data

- **Tasks are ephemeral, retention-bound records.** They are written per request, re-read for a bounded window (`GetTask`/`ListTasks`), and then expire. MongoDB TTL indexes handle retention natively (one index on an `updated_at` field); with SQL backends every deployment has to build its own cleanup job (cron / `EVENT` scheduler / partition rotation).
- **Many A2A server deployments already run a document store** for conversation state, and adding a relational database + Alembic migrations solely for task persistence is a heavy dependency for what is a single-collection workload.

## Implementation notes (lessons that may save others time)

We verified these against SDK 1.1.2 semantics; happy to carry them into a PR:

1. **Store the `Task` as serialized proto bytes, not ProtoJSON.** `Task.metadata` is a proto `Struct` with arbitrary client-supplied keys — keys containing `.` or `$` become invalid MongoDB document keys after `MessageToDict`. Storing `task.SerializeToString()` as opaque bytes (plus a handful of extracted top-level fields for querying: owner, `context_id`, `status.state`, `status.timestamp`) is exact, round-trip safe, and resilient to unknown fields across SDK upgrades.
2. **Owner partitioning parity.** All reads/writes are scoped by `owner_resolver(context)` (default `resolve_user_scope`), matching `InMemoryTaskStore` — including refusing cross-owner access on `get`/`delete`.
3. **Pagination matching in-memory semantics.** Sort `(status.timestamp desc — nulls last, id desc)`; the page token (`encode_page_token`) is the id of the first item of the requested page (inclusive anchor), so the store re-resolves the anchor document to build a `(timestamp, id)` cursor filter; unknown tokens raise `InvalidParamsError`. MongoDB's BSON ordering (`Date > Null` under descending sort) reproduces the in-memory null-handling exactly.
4. **`get_info_for_dispatch` must be overridden** on custom `PushNotificationConfigStore` implementations (the base fallback silently drops notifications for authenticated owners — the docstring warns about this, but it is easy to miss). Since streaming turns call it once per emitted event, we front it with a short (5s) in-process memo keyed by `task_id`, invalidated on `set_info`/`delete_info`.

The whole thing is ~200 lines for both stores. Deployed behind a FastAPI JSONRPC server; verified: task survives process restart and is served by a different replica, `ListTasks` cursor pagination over 100+ tasks, push configs dispatching across replicas.

## Questions for maintainers

1. Is there interest in an official NoSQL backend, and if so, would you prefer an optional extra (`a2a-sdk[mongodb]`, pymongo async client) or a documented recipe in the docs/examples?
2. If an extra: should it mirror `DatabaseTaskStore`'s constructor conventions (`create_table` → `ensure_indexes`, `owner_resolver` injection), and should retention (TTL) be part of the contract or left to operators?
3. Would you want the same treatment for `PushNotificationConfigStore` in the same PR?

If maintainers are open to it, we're happy to submit the PR with tests (the store semantics above are covered by a small in-memory fake collection in our suite; we can port those tests).

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.