← 返回藏书阁

A2A Jakarta:跨节点状态复制不等于生产安全与故障恢复

wiki/ai/sources/a2a-jakarta-cross-node-state-and-effective-security.md
分类:ai / sources · 更新:2026-10-24 09:11

A2A Jakarta:跨节点状态复制不等于生产安全与故障恢复

知识点轴:A2A / harness-runtime / sandbox-security。 价值不是又一个 SDK release,而是一个可逐文件核对的双节点案例:共享持久状态与复制实时事件各司其职;SDK 的安全默认值,却被示例配置主动关闭。

为什么值得深挖

Hermes 若把长任务委托给远端 agent,断流后的客户端可能连接到另一实例。单机 TaskHandle 能拿到任务 ID,不代表新节点知道历史状态、能收到后续事件或能安全继续工作。此案例把 A2A-Agent2Agent-Protocol 的任务协议落到 Harness-Engineering 的状态/事件基础设施,比仅可读 Agent Card 多了一层工程证据;不是用户系统的部署推荐。

来源与版本边界

  • WildFly 公告 发布于 2026-09-10,声明 Jakarta 1.0.0.Final 支持 A2A 1.0、JSON-RPC/gRPC/REST 和 0.3 兼容层。
  • 固定仓库 wildfly-extras/a2a-jakarta,commit d611c7c336948c12dab20f4e46d324a22a492e41。根 pom.xml 的 version.sdk=1.3.2.Final、version.wildfly=41.0.1.Final 与公告一致。
  • 文档争议:同 tag 根 README 仍写 SDK 1.0.0.Final。本页按 POM/公告记录依赖版本,保留 contested: true 提醒文档未同步;未执行 dependency resolution,所以不是实际 WAR 依赖清单。
  • 已读公告、上游 1.3.0 安全迁移说明、企业 README、Card/executor/client、配置及一个多租户 JSON-RPC 测试包装类。GitHub API 限流,未取得可靠当前 star 数;不影响固定 tag 代码取证。^[raw/articles/a2a-jakarta-cross-node-state-and-effective-security-2026-09-13.md]

2026-10-24 版本核对:1.1.0 并未消除示例边界

2026-10-21 官方公告 将 Jakarta 升到 1.1.0.Final、上游 SDK 升到 1.4.0.Final。固定 tag 对应 commit d712ac1ecbfa4c7bac4d3983f6e88b09d43c2587,根 POM 确认 version.sdk=1.4.0.Final、WildFly 仍 41.0.1.Final。上游 SDK release 发布于 09-28;不能把 10-21 集成公告当作新协议版本,也不重造一篇 release 薄页。旧 tag 的 README/POM 分歧仍属历史版本证据,本次未重新取根 README 判其已修。^[raw/articles/a2a-jakarta-110-java-140-pinned-enterprise-2026-10-24.md]

SDK 公告把 @Tenant qualifier 移到 server-common,以解决默认/tenant Card 的 CDI 选择与歧义;重复 extended Card 启动拒绝、SSE 每行默认限制增至 1 MB、application/a2a+json 兼容等也有说明。这是上游公告/完整 release notes 层证据,不是本轮逐项审计上游实现或运行通过;Card 路由修复并不自动建立 caller→task owner 授权。^[raw/articles/a2a-jakarta-110-java-140-pinned-enterprise-2026-10-24.md]

本轮固定企业 config/Card/client/README 仍见 a2a.authorization.required=false、每节点独立 Kafka group.id、B 续订后 Thread.sleep(1000),随后真实工作继续交给 A;只改集成版本不能推出安全默认已在该示例生效、订阅显式 ready 或 A 故障后可接管。归档 README 的 expected output 不是本机结果;未启动 Java、PostgreSQL/Kafka 或发送 Task。与 ssr-agent-discovery-candidate-context-and-retrieval-boundaries 并读:后者的 E2E 只到候选选择,本例才涉及任务/事件基础设施,但两者都不能替代实际部署的 owner、断流和业务 effect 验收。^[raw/articles/a2a-jakarta-110-java-140-pinned-enterprise-2026-10-24.md]

机制:状态存储、事件传播和执行恢复是三件事

  1. 状态面:两个 WildFly 节点共用 PostgreSQL;JPA TaskStore 和 PushNotificationConfigStore 替换内存实现,保存任务及推送配置。示例使用非破坏性 schema update,不应将启动 B 等同重建 A 的库。
  2. 事件面:Kafka-backed ReplicatedQueueManager 传播 live events。示例要求每节点独立 group.id,让 A/B 都收到同一 topic 的事件;共享 consumer group 的分摊消费不能直接替代这一广播语义。
  3. 演示路径:客户端从 A/B 各自解析 Card;向 A 发 messageId="init" 建任务,在 B subscribeToTask,再向 A 发带同一 taskId 的 continuation。A 产生 working → artifact → completed,B 收集状态与产物。init 是 executor 明写的 demo-only 约定,不是 A2A 标准握手。
  4. 恢复面未证明:A 仍负责实际执行,B 是观察者。本路径没有展示 A 宕机后的工作接管、业务动作幂等或跨节点取消。因此共享 task DB + 事件复制不推出执行 exactly-once 或 HA 完成保证。^[raw/articles/a2a-jakarta-cross-node-state-and-effective-security-2026-09-13.md]

这与 a2a-query-task-handle-approval-broker 互补:后者强调客户端状态句柄/重订阅,本文补服务端跨节点的共享状态与事件传播。MCP-Gateway-Runtime 的负载均衡或 session affinity 只能选路,不能替代任务状态协议。

对照2026-09-29发布的 a2a-python-cluster-state-stream-execution-boundaries:另一SDK以任务修订CAS、共享事件表和请求边界刷新支持跨副本读/续写/取消;它也未由此证明执行接管、跨租户身份或业务副作用只执行一次。两套实现需分别核各自SDK版本/有效配置,不可把一家的验收结论移接到另一家。

最重要反例:默认值与有效配置相反

上游 1.3.0 公告称未配置 TaskAuthorizationProvider 时默认拒绝任务操作,并将检查移入 DefaultRequestHandler 覆盖 CDI/builder 路径。这是 SDK 公告层证据,不是本机对实现的安全审计。固定 tag 的企业示例却明确配置 a2a.authorization.required=false。 把「SDK fail-closed」与「企业示例」两句话拼在一起,会制造不存在的授权保证。^[raw/articles/a2a-jakarta-cross-node-state-and-effective-security-2026-09-13.md]

多租户 MultiTenantJsonRpcTest 继承上游抽象测试并加载专用 fixture:同样关闭 authorization,而且 org.a2aproject.sdk.transport.skipValidation=true,注释说明共享 Card 宣告了该部署未装入的 HTTP_JSON transport。路由测试不等于租户授权或 Card 全能力验证;本次也未阅读继承父类的所有断言或运行测试。^[raw/articles/a2a-jakarta-cross-node-state-and-effective-security-2026-09-13.md]

失败模式与最小接入验收

观察到的具体边界不能推出的结论建议隔离验证
B 订阅后固定 Thread.sleep(1000) 再驱动 A订阅已经就绪、早期事件必达用显式订阅就绪信号;断流/晚订阅后 getTask 对账
executor cancel() 抛 TaskNotCancelableErrortask API 存在就可取消工作验证不可取消响应,不自动重发有副作用任务
每节点独立 consumer group生产任意分区/分组布局都广播正确对比共享组、独立组、重启/重复事件
JPA push-config store 已装入实际 push 已开启或 webhook 安全单独核 Card、push enablement、目的地策略及回调回执
demo 关闭授权、gRPC 使用 plaintext企业多租户隔离或 TLS 已满足加真实 provider/TLS,测试 A 身份读取/续写 B 的任务

对 Hermes / llm-wiki 的可执行启发

  • 在接入记录分开保存 SDK 默认值 / 示例 override / 测试 fixture / 实际部署配置,不能只抄 README 安全卖点。
  • 任务结果区分「可查历史」「能订阅后续事件」「可恢复执行」「业务只执行一次」;用 Agent-Benchmarks 为每项单独设计断言。
  • 沿用 a2a-tck-conformance-coverage-and-security-boundaries:记录跳过的校验及其原因,不将测试类名称、声明 transport 或示例 expected output 当运行通过。

本轮验证与未执行项

本机解析固定 tag 文件并完成 12 项静态断言,核对 POM、关闭授权、广播分组、demo init、取消拒绝、订阅 sleep、streaming Card、fixture 和 README/POM 差异。结果在 raw/notes/ai-knowledge-radar-2026-09-13.md。没有编译/启动 Java、Kafka/PostgreSQL,没有跑 TCK、task E2E、鉴权/崩溃恢复测试。 原文示例输出不作为本机结果。

写入记录

  • 2026-09-13 09:14 CST:新增固定 tag 双节点机制分析,核对 12 项静态配置/源码事实;显式区分 SDK 默认、demo override、fixture 和真实部署,保留 README 版本分歧及未验证恢复边界。
  • 2026-10-07 09:05 CST:新增A2A Python 1.2跨副本状态/事件与执行接管分验反链;不更改Jakarta原始证据范围。
  • 2026-10-24 09:10 CST:固定 Jakarta 1.1.0.Final 企业配置/POM/Card/client 与 SDK 1.4 公告;确认关闭授权、广播与订阅 sleep 仍在,区分版本更新、发现选择和真实任务验收,不声称部署复现。