Repository navigation
[ISSUE #5405] A2A gateway production wiring: main-process boot, RocksDB task store, auth, metrics, contextId - #5406
Merged
Conversation
… RocksDB task store, auth, metrics, contextId The A2A gateway was component-complete but never wired for production: EventMeshA2ATransport (the real transport bridged onto UniIngressService) existed unused, EventMeshApplication never booted the gateway, and the only TaskStore backend required Nacos. - EventMeshApplication.withA2aGateway(...): boots the Netty REST plane (/a2a/*) with the main process, wired onto the REAL transport, plus a TaskExpirer reaper. Opt-in via -Deventmesh.a2a.enabled=true, port -Deventmesh.a2a.port=10108, graceful shutdown included. - RocksDBTaskStore: local durable TaskStore under <data>/a2a-tasks (same dir layout as offsets/delivery-state), wire-format compatible with the MetaBacked v1 envelope. Default when no Meta is configured; -Deventmesh.a2a.taskstore=meta selects the cluster-shared store. - Bearer-token auth on the gateway REST plane (-Deventmesh.a2a.token, constant-time compare, same pattern as the admin token guard apache#5364); without a token the gateway is open (dev mode, logged at boot). - A2A metrics: submitted/completed/failed/canceled/expired counters plus an active-task gauge, surfaced via /admin/metrics JSON and the /metrics Prometheus scrape. - Traffic-port guidance (apache#5225 class confusion): a JSON-RPC body posted to /events/publish now returns a 400 pointing at the A2A gateway endpoints instead of an opaque CloudEvent transform error. - contextId passthrough (issue apache#5405): optional conversation linkage on task submit, persisted in TaskRecord (10th wire field, v1 readers ignore the suffix), echoed in snapshots. Tests: RocksDBTaskStoreTest (round-trip, epoch CAS, duplicate rejection, contextId persistence, expiry, reopen durability) and A2AGatewayWiringTest (main-process boot + health, token 401/200, contextId through the REST round-trip into the durable store).
qqeasonchen
force-pushed
the
a2a/production-wiring
branch
3 times, most recently
from
September 21, 2026 02:30
7b492db to
d4fda7b
Compare
…dening Gateway plane (items 1-6): main-process boot via withA2aGateway + -Deventmesh.a2a.enabled=true (port 10108) on the REAL transport (EventMeshA2ATransport -> UniIngressService); RocksDBTaskStore local default (<data>/a2a-tasks, MetaBacked-compatible v1 wire format); bearer-token auth (-Deventmesh.a2a.token, constant-time); A2A metrics in /admin/metrics and the /metrics Prometheus scrape; traffic-port guidance for apache#5225-style JSON-RPC misposts; contextId conversation linkage persisted and echoed. Agent plane (items 7-11): default agent.runtime.url 8080 -> 10105; new bin/start-agent.sh launcher (the dist-agent task referenced a bin/ that never existed); ConversationStore bounded conversation count with access-order LRU eviction (agent.conversation.maxConversations); fail-fast on an empty llm.api.key (llm.api.key.optional=true opts out for mock gateways); heartbeat consecutive-failure limit (agent.heartbeat.failLimit, default 6) exits the process for supervisor restart instead of serving as a zombie; new docs/feature/agent.md. Bug fix found by the new wiring test: A2AGatewayHttpHandler lacked @sharable - the gateway could only ever serve ONE HTTP connection (the second channel hit ChannelPipelineException; all existing tests used a single request). A2AGatewayServer.getPort() now resolves the auto-selected port (0). Also normalizes the nonstandard license headers on 8 deploy/kubernetes/*.yaml files (apache#5398 leftovers) so the license check passes. Tests: RocksDBTaskStoreTest (7), A2AGatewayWiringTest (3), agent ConversationStoreTest (+2: LRU eviction, unbounded-compat), existing a2a suite green; checkstyleMain/Test clean; dependency-review green.
qqeasonchen
force-pushed
the
a2a/production-wiring
branch
from
September 21, 2026 02:35
d4fda7b to
59df396
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5405
What
Two planes in one PR — the A2A gateway (items 1-6 of the issue) and the v2 agent process (items 7-11).
A2A gateway (production wiring)
EventMeshApplication.withA2aGateway(...)+-Deventmesh.a2a.enabled=true(port10108,EVENTMESH_A2A_*envs) — wired onto the REAL transport (EventMeshA2ATransport→UniIngressService), withTaskExpirerand graceful shutdown. Previously this transport class existed unused.RocksDBTaskStore— local durable task store under<data>/a2a-tasks, wire-format compatible with the MetaBacked v1 envelope;-Deventmesh.a2a.taskstore=metaselects the cluster-shared store.-Deventmesh.a2a.token, constant-time; empty = open dev mode, logged)./admin/metricsand the/metricsPrometheus scrape./events/publishgets a 400 pointing at the A2A gateway.contextIdconversation linkage: submitted, persisted (10th wire field, older readers ignore), echoed in snapshots.Agent process (hardening)
agent.runtime.url8080→10105(port-migration leftover — the agent could not reach a default runtime).bin/start-agent.shlauncher — thedist-agentgradle task referenced aneventmesh-agent/bin/that never existed; the distribution had no launcher whileagent.propertiesdocumented one.ConversationStorebounded conversation count with access-order LRU eviction (agent.conversation.maxConversations, default 1000) — the per-conversation window existed but session count grew without bound.get()of an unknown id no longer resurrects the key (admit vs refresh semantics).llm.api.key(opt out viallm.api.key.optional=truefor mock gateways) — a READY agent without a key failed every routed request.agent.heartbeat.failLimit, default 6) exits the process for supervisor restart instead of serving as a zombie after the runtime TTL eviction.Bug fix found by the new wiring test:
A2AGatewayHttpHandlerlacked@Sharable— the gateway could only ever serve ONE HTTP connection (the second channel hitChannelPipelineException; existing tests all used a single request).A2AGatewayServer.getPort()resolves the auto-selected port (0).Also normalizes nonstandard license headers on 8
deploy/kubernetes/*.yaml(#5398 leftovers) so the license check passes.New docs:
docs/feature/agent.md(boot sequence, config table, reliability behavior).Testing (local, full gradle gates)
RocksDBTaskStoreTest7/7;A2AGatewayWiringTest3/3ConversationStoreTest7/7 (incl. LRU eviction + unbounded-compat),OpenAiLlmClientTest3/3SmokeTest,FailureModeTest,ServiceTest,ExpirerTest); checkstyleMain/Test clean on both modules