Audience: anyone choosing a wire protocol or SDK. The canonical inventory of protocols, server-side plugins, and client SDKs, with GA / Beta / Experimental / Legacy status (README table is authoritative).
This issue tracks the separation called out in #5296 review question Q5 (2026-09-07): the modern HTTP + CloudEvents + EventMeshFrame path must be the only one downstream code depends on, while the legacy TCP, gRPC, and OpenMessaging paths must be clearly marked and isolated from the modern SDK public surface.
| Protocol | Status | Wire format | Where it lives | Replacement |
|---|---|---|---|---|
| CloudEvents 1.0 over HTTP | GA | CloudEvents JSON (binary-mode optional) | runtime ingress / egress (HTTP), eventmesh-protocol-plugin/eventmesh-protocol-cloudevents | - |
| EventMeshFrame (internal) | GA | org.apache.eventmesh.common.wire.EventMeshFrame (Frame architecture) | runtime internal; producer / storage / push path | - |
| A2A (Agent-to-Agent) | Experimental | A2A JSON-RPC + SSE | eventmesh-protocol-plugin/eventmesh-protocol-a2a, A2A gateway on Runtime | - |
| MeshMessage TCP | Legacy | length-prefixed MeshMessage bytes | runtime tcp/ subpackage, eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/resolver/tcp | CloudEvents HTTP, or A2A (for agent workloads) |
| gRPC (CloudEvents + EventMeshMessage) | Beta | protobuf over HTTP/2 | runtime grpc/ bridge (issue #5411), eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/resolver/grpc | CloudEvents HTTP for new clients |
| OpenMessaging API (TCP) | Legacy | OMA spec, used by the legacy TCP client only | eventmesh-sdks/eventmesh-sdk-java/client/tcp/impl/openmessage | CloudEvents HTTP client |
GA = production-ready and the recommended path. Beta = stable but the API surface may still shift. Experimental = subject to breaking change without notice. Legacy = still works, but is no longer the recommended choice and is being phased out.
The v2 runtime serves the legacy SDK gRPC protocol as a compatibility bridge on eventmesh.grpc.port (1.x default 10205; unset / -1 = disabled, opt-in like the WS port). There is no second messaging engine: every call maps onto the same v2 ingress/delivery pipeline the HTTP plane uses (WAL durability, at-least-once, shared retry/DLQ).
| Legacy call | v2 mapping |
|---|---|
publish / batchPublish / publishOneWay / batchPublishOneWay | proto CloudEvent → v2 CloudEvent, persisted via UniIngressService.publish (topic = proto subject attribute) |
requestReply | v2 request/reply correlation (UniIngressService.request), TTL attribute drives the timeout |
subscribe (webhook url) | WebHookChannel push target + v2 subscription per topic |
subscribeStream (bidi) | GrpcStreamChannel push target pumping the v2 dispatcher into the stream; ACKs ride back as stream replies |
unsubscribe | v2 unsubscribe per topic + client deregistration |
heartbeat | TTL refresh in the GrpcClientRegistry; a reaper evicts stale clients (unsubscribes them) |
Group semantics: the legacy consumerGroup maps onto a v2 subscription group; the SDK's default CLUSTERING mode maps to LOAD_BALANCE distribution, BROADCASTING maps to BROADCAST. The clientId is derived from consumerGroup + env + idc (the 1.x triple).
Non-goals (follow-ups): a new gRPC-native v2 API (HTTP + CloudEvents stays the primary path), the gRPC admin surface (stays unimplemented as on 1.x), and Go/Rust SDK verification (the protos are shared; Java SDK is the conformance suite — see GrpcLegacyBridgeIntegrationTest).
The runtime discovers protocol adaptors via the org.apache.eventmesh.protocol.api.ProtocolAdaptor SPI. Active plugins:
eventmesh-protocol-plugin/eventmesh-protocol-cloudevents - GA. HTTP publish / subscribe over CloudEvents JSON. Required by the modern data plane. Do not deprecate.eventmesh-protocol-plugin/eventmesh-protocol-meshmessage - Beta as the HTTP / gRPC resolver package, Legacy as the TCP resolver package. The HTTP and gRPC surfaces remain because they carry EventMeshMessage semantics (used by some existing gRPC clients); the TCP surface is in maintenance mode and receives only critical bug fixes.eventmesh-protocol-plugin/eventmesh-protocol-a2a - Experimental. A2A wire contract; routes tasks through the A2A gateway on Runtime.The eventmesh-architecture-guard module enforces that connector plugins do not depend on eventmesh-runtime; the protocol plugins are the runtime's internal extension point and live under eventmesh-protocol-plugin/. Downstream consumers should not depend on any of the protocol plugins directly - they should depend on the SDK (see section 3).
| SDK | Path | Status | Notes |
|---|---|---|---|
| Java (CloudEvents) | eventmesh-sdks/eventmesh-sdk-java/client/cloudevents | GA | The only modern SDK client. Recommended for all new code. |
| Java (gRPC) | eventmesh-sdks/eventmesh-sdk-java/client/grpc | Beta | For clients that need gRPC framing; backed by the gRPC resolver. |
| Java (TCP) | eventmesh-sdks/eventmesh-sdk-java/client/tcp | Legacy | Includes the openmessage, cloudevent, and eventmeshmessage impls. The OpenMessaging impl is being phased out (see migration below). |
| C | eventmesh-sdks/eventmesh-sdk-c | Beta | HTTP + CloudEvents. |
| Go | eventmesh-sdks/eventmesh-sdk-go | Beta | HTTP + CloudEvents. |
| Rust | eventmesh-sdks/eventmesh-sdk-rust | Beta | HTTP + CloudEvents. |
Starting with this release, the Java SDK's public API surface - i.e. the classes that downstream consumers should reference - is restricted to:
org.apache.eventmesh.client.cloudevents.CloudEventsClient (and the client/cloudevents/stream/* types for streaming / SSE).org.apache.eventmesh.client.grpc.* (for clients that need gRPC).Anything under org.apache.eventmesh.client.tcp.* is marked Legacy and is excluded from the SDK‘s api configuration in Gradle. The io.openmessaging:openmessaging-api dependency, which is only used by the legacy TCP client’s OpenMessaging implementation, is demoted from api to implementation so that modern users (who only depend on the CloudEvents client) do not see OMA types in their classpath.
org.apache.eventmesh.client.cloudevents.CloudEventsClient (see docs/feature/client-java.md).EventMeshMessage / OMA Message envelope. Event payload stays the same.eventmesh-architecture-guard enforces, via ArchUnit rules and the architecture-guard.yml CI workflow, that:
eventmesh-protocol-plugin/* modules are partitioned into public (SPI) and internal (implementation); the public -> internal direction is allowed, the reverse is not (see #5297).eventmesh-connector-plugin/* may not depend on eventmesh-runtime (see #5302 / #5297).UniIngressService, UniHttpServer) may not import legacy TCP / OMA wire types (verified by git grep "import.*MeshMessage\\|import io.openmessaging" in eventmesh-runtime/src/main/ - only the legacy tcp/ and transport/http/LegacyHttp* packages should match).For the #5341 acceptance check, the following must hold:
docs/feature/protocols.md exists and is linked from docs/architecture/overview.md (section 9) and from the README.build.gradle declares io.openmessaging:openmessaging-api as implementation, not api.git grep "import.*MeshMessage\\|import io.openmessaging" in eventmesh-runtime/src/main/ returns only files under runtime/tcp/, runtime/transport/http/LegacyHttp*, or runtime/transport/http/EventMeshMessageHttpCodec (the legacy HTTP codec).eventmesh-architecture-guard continues to pass on the develop branch after these changes.docs/architecture/overview.mddocs/feature/client-java.mdeventmesh-architecture-guard/, docs/feature/architecture-guard.mddocs/feature/a2a.md