| # Apache EventMesh Features |
| |
| > **Status:** Living document. Reflects the post-#5296 architecture-review state |
| > of the `develop` branch. The **capability status table** in the project README |
| > is the single source of truth for GA / Beta / Experimental / Legacy tags; this |
| > page describes *what each feature does* and *where the code lives*. |
| > |
| > See [docs/eventmesh-architecture.md](eventmesh-architecture.md) for the |
| > structural view (control / data / agent planes) and |
| > [docs/eventmesh-configuration.md](eventmesh-configuration.md) for the keys |
| > that turn each feature on. |
| |
| This page is organized by **user intent**: a user who wants to publish events, |
| who wants to subscribe, who wants to wire a multi-agent system, who wants to |
| add a new storage backend, who wants to deploy at scale, and who wants to |
| operate the cluster. Each section points at the exact code locations you can |
| read to go deeper. |
| |
| --- |
| |
| ## 1. CloudEvents-native publish / subscribe |
| |
| **What it is.** The primary user path. A Java client uses |
| `CloudEventsClient` to `publish` and `subscribe` over plain HTTP, with the |
| event body in [CloudEvents 1.0](https://cloudevents.io) format. The runtime |
| treats the broker as a pure write-ahead log; **all subscription semantics |
| live in the runtime**, not the broker. |
| |
| **Why it matters.** Vendor-neutral events; no client-side knowledge of the MQ; |
| horizontal scale-out is a config change; reliability is owned by the runtime |
| through self-managed offsets + explicit ACK. |
| |
| **Where the code lives.** |
| |
| * Client: `eventmesh-sdks/.../cloudevents/CloudEventsClient.java` |
| * Walkthrough: [docs/eventmesh-client-guide.md](eventmesh-client-guide.md) |
| * Runtime HTTP entry: `eventmesh-runtime/.../http/UniHttpServer.java` |
| * Ingress: `eventmesh-runtime/.../ingress/UniIngressService.java` |
| * Producer (MQ-as-WAL writer): |
| `eventmesh-runtime/.../protocol/producer/Producer.java` |
| * Subscribe: `eventmesh-runtime/.../protocol/subscribe/SubscribeProcessor.java` |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.runtime.http.port = 10106 |
| eventmesh.runtime.http.tls.enabled = true |
| eventmesh.runtime.subscriptions.maxPerClient = 1000 |
| ``` |
| |
| See [docs/eventmesh-configuration.md](eventmesh-configuration.md#publishsubscribe) |
| for the full list. |
| |
| --- |
| |
| ## 2. Multiple subscriber transports |
| |
| **What it is.** A subscriber picks one of three delivery transports at |
| `POST /events/subscribe` time: |
| |
| | Transport | Endpoint | Use case | |
| | --- | --- | --- | |
| | HTTP long-polling | `POST /events/subscribe` (default) | Best fit for batch backends, scheduled jobs, serverless | |
| | Server-Sent Events | `POST /events/subscribeSse` | Browser / mobile push, one-way streaming | |
| | WebSocket | `POST /events/subscribeWs` | Bi-directional push, low-latency interactive clients | |
| | Request-reply | `POST /events/request` + `POST /events/reply` | RPC-style synchronous call (built on top of the same MQ-as-WAL pipe) | |
| |
| **Why it matters.** Different consumers have different latency / connection |
| profiles. EventMesh does not force a one-size-fits-all transport; the runtime |
| fan-out is shared so reliability and quota are uniform. |
| |
| **Where the code lives.** |
| |
| * Long-poll: `eventmesh-runtime/.../protocol/subscribe/SubscribeProcessor.java` |
| * SSE: `eventmesh-runtime/.../protocol/subscribe/SseProcessor.java` |
| * WebSocket: `eventmesh-runtime/.../http/UniWsServer.java` |
| * Request-reply: `eventmesh-runtime/.../protocol/subscribe/RequestReplyProcessor.java` |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.runtime.sse.heartbeatIntervalMs = 15000 |
| eventmesh.runtime.ws.maxFrameSize = 65536 |
| eventmesh.runtime.request.reply.timeoutMs = 30000 |
| ``` |
| |
| --- |
| |
| ## 3. Reliable delivery: at-least-once, retries, dead-letter |
| |
| **What it is.** Every delivery is tracked by a `DeliveryStateStore`. On ACK |
| the runtime advances the offset; on failure it retries with backoff; on |
| terminal failure the event is moved to a `DeadLetterStore`. Operators can |
| inspect and replay from the dead-letter store. |
| |
| **Why it matters.** When the broker is just a WAL, *the runtime* must own |
| delivery. The storage SPI does not know what is consumed; the runtime |
| decides when to advance, when to retry, and when to give up. |
| |
| **Where the code lives.** |
| |
| * State: `eventmesh-runtime/.../state/DeliveryStateStore.java` |
| * Dead-letter: `eventmesh-runtime/.../state/DeadLetterStore.java` |
| * Reliable dispatcher: `eventmesh-runtime/.../protocol/producer/ReliableDispatcher.java` |
| * Retry policy: `eventmesh-common/.../retry/RetryPolicy.java` |
| * Tests: `eventmesh-runtime/.../state/DeliveryStateStoreTest.java` |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.runtime.delivery.maxRetries = 5 |
| eventmesh.runtime.delivery.backoff.initialMs = 500 |
| eventmesh.runtime.delivery.backoff.maxMs = 30000 |
| eventmesh.runtime.deadletter.topic = eventmesh-deadletter |
| ``` |
| |
| --- |
| |
| ## 4. Unified state control plane (issue #5301) |
| |
| **What it is.** Before #5301 the runtime had half a dozen overlapping state |
| APIs (`PartitionOwnership`, `MetaBackedOffsetStore`, `ClusterCoordinator`, |
| in-memory `TaskRegistry` for A2A). #5301 consolidated them into a small, |
| federated set of *capability-typed* stores: |
| |
| | Level | Interface | Default backend | Purpose | |
| | --- | --- | --- | --- | |
| | L1 — local-only | `OffsetStore` | RocksDB or local KV | per-instance delivery hints | |
| | L2 — cluster-shared | `SubscriptionStore`, `SessionStore` | Meta store (Nacos / Consul / ETCD / ZK) | subscription / session / agent-card registry | |
| | L3 — durable-egress | `DeadLetterStore`, `TaskStore` | Meta store (CAS + epoch) | dead-letter, A2A task records | |
| |
| **Why it matters.** One contract per concern, one TCK per contract, and the |
| fencing token on the L2/L3 stores makes split-brain impossible to corrupt |
| state. Adding a new meta backend (e.g. Eureka) is now a single |
| `MeshStoragePlugin` implementation that passes the TCK. |
| |
| **Where the code lives.** |
| |
| * Interfaces: `eventmesh-storage-plugin/eventmesh-storage-api/.../storage/MeshStoragePlugin.java` |
| * TCK: `eventmesh-storage-plugin/eventmesh-storage-api/.../storage/tck/MeshStoragePluginTCK.java` |
| * Capability flags: `eventmesh-storage-plugin/eventmesh-storage-api/.../storage/StorageCapabilities.java` |
| * Meta-side adapters: `eventmesh-runtime/.../cluster/ClusterSubscriptionStore.java`, |
| `eventmesh-runtime/.../session/SessionRegistry.java`, |
| `eventmesh-runtime/.../a2a/A2AGatewayService.java` |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.storage.meta.backend = nacos |
| eventmesh.storage.meta.nacos.serverAddr = nacos:8848 |
| eventmesh.storage.local.backend = rocksdb |
| eventmesh.storage.local.rocksdb.path = /var/lib/eventmesh/offset |
| ``` |
| |
| --- |
| |
| ## 5. Unified security gate (issue #5304) |
| |
| **What it is.** An opt-in gate that runs on every ingress point |
| (`UniHttpServer`, `A2AGatewayHttpHandler`, `ConnectorScheduler`). The gate |
| composes the existing `FilterChain` (auth + ACL) with a per-tenant |
| `QuotaManager` and an `AuditSink`. |
| |
| **Order of checks.** `FilterChain.invoke` → (on allow) `QuotaManager.acquire` → |
| `AuditSink.emit`. Rejecting at any step short-circuits downstream and the request |
| never touches the storage SPI. |
| |
| **Why it matters.** A single, composable policy point is the only way to |
| guarantee that quota / audit / ACL are not forgotten in a new endpoint. The |
| gate is opt-in so legacy deployments keep working, but new endpoints are |
| expected to install it. |
| |
| **Where the code lives.** |
| |
| * Package: `eventmesh-runtime/.../security/gate/` |
| * Core: `SecurityGate.java`, `RequestContext.java`, `GateDecision.java` |
| * Quota: `QuotaManager.java`, `UnlimitedQuotaManager.java`, `TenantQuotaManager.java` |
| * Audit: `AuditSink.java`, `LoggingAuditSink.java`, `DisabledAuditSink.java` |
| * Wiring: |
| * `eventmesh-runtime/.../http/UniHttpServer.java#withSecurityGate` |
| * `eventmesh-runtime/.../a2a/A2AGatewayHttpHandler.java#withSecurityGate` |
| * `eventmesh-runtime/.../connector/ConnectorScheduler.java#withSecurityGate` |
| * Tests: `eventmesh-runtime/.../security/gate/SecurityGateTest.java` (10 tests) |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.security.gate.enabled = true |
| eventmesh.security.gate.quota.connections.perTenant = 10000 |
| eventmesh.security.gate.quota.subscriptions.perTenant = 1000 |
| eventmesh.security.gate.quota.throughput.bytesPerSec = 1048576 |
| eventmesh.security.gate.audit.sink = logging |
| ``` |
| |
| For the wiring contract and the full list of `RequestContext` fields, see |
| [docs/eventmesh-architecture.md §4](eventmesh-architecture.md#4-security-gate-issue-5304). |
| |
| --- |
| |
| ## 6. Agent-to-Agent (A2A) protocol |
| |
| **What it is.** A2A is the [Agent-to-Agent](eventmesh-a2a-protocol.md) contract — a |
| task lifecycle (`submitted → working → completed | failed | canceled`) on |
| top of CloudEvents, with **durable** task records in the meta store. EventMesh |
| acts as the gateway: it accepts `tasks/send`, dispatches to the target agent |
| via a topic, and streams replies back over `/a2a/tasks/{taskId}/stream`. |
| |
| **Why it matters.** A2A turns EventMesh into an **agent bus**. Synchronous |
| MCP / JSON-RPC 2.0 tool calls and asynchronous pub/sub share the same |
| storage, the same quota, the same audit, and the same reliability layer. The |
| A2A `taskEpoch` field is the cross-agent idempotency key. |
| |
| **Where the code lives.** |
| |
| * Wire spec: [docs/eventmesh-a2a-protocol.md](eventmesh-a2a-protocol.md) |
| * Service: `eventmesh-runtime/.../a2a/A2AGatewayService.java` |
| * Topic convention: `eventmesh-protocol-plugin/eventmesh-protocol-a2a/.../A2ATopicFactory.java` |
| (`agentInbox(agentId)`, `gatewayResponseTopic(ns, gw, taskId)`) |
| * Runtime bridge: `eventmesh-runtime/.../a2a/EventMeshA2ATransport.java` |
| * HTTP handler: `eventmesh-runtime/.../a2a/A2AGatewayHttpHandler.java` |
| * Server (Netty): `eventmesh-runtime/.../a2a/A2AGatewayServer.java` |
| * Agent cards: `eventmesh-runtime/.../a2a/AgentCardRegistry.java` + |
| `InMemoryAgentCardRegistry.java` |
| * Example agent: `eventmesh-agent/.../Agent.java` |
| |
| **Status.** **Experimental.** The wire format and the task lifecycle are |
| stable; the reaper and the Meta-backed `AgentCardRegistry` are pending (D2 of |
| issue `#5302`). |
| |
| --- |
| |
| ## 7. Pluggable storage backends |
| |
| **What it is.** Every state store (`OffsetStore`, `SubscriptionStore`, …) is |
| an SPI. Backends currently shipping: |
| |
| * **RocketMQ** — `eventmesh-storage-plugin/eventmesh-storage-rocketmq/` |
| * **Kafka** — `eventmesh-storage-plugin/eventmesh-storage-kafka/` |
| * **Pulsar** — `eventmesh-storage-plugin/eventmesh-storage-pulsar/` |
| * **RabbitMQ** — `eventmesh-storage-plugin/eventmesh-storage-rabbitmq/` |
| * **Redis** — `eventmesh-storage-plugin/eventmesh-storage-redis/` |
| * **RocksDB** (local) — `eventmesh-storage-plugin/eventmesh-storage-rocksdb/` |
| (L1, no meta store required) |
| |
| **Why it matters.** A new backend (Pravega, AutoMQ, …) is one module that |
| implements `MeshStoragePlugin` and passes `MeshStoragePluginTCK`. There is no |
| fork; there is no runtime patch. |
| |
| **Where the contract lives.** |
| |
| * `eventmesh-storage-plugin/eventmesh-storage-api/.../storage/MeshStoragePlugin.java` |
| * `eventmesh-storage-plugin/eventmesh-storage-api/.../storage/StorageCapabilities.java` |
| — capability flags (`OFFSET_TRACKING`, `PREFIX_WATCH`, `CAS`, …) so the |
| runtime knows what a backend can do without a feature-detect probe. |
| * `eventmesh-storage-plugin/eventmesh-storage-api/.../storage/tck/MeshStoragePluginTCK.java` |
| — the test every backend must pass before it can ship. |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.storage.meta.backend = nacos |
| eventmesh.storage.local.backend = rocksdb |
| eventmesh.storage.rocketmq.namesrvAddr = rocketmq:9876 |
| eventmesh.storage.kafka.bootstrapServers = kafka:9092 |
| ``` |
| |
| --- |
| |
| ## 8. Connector ecosystem (24+ plugins) |
| |
| **What it is.** Connectors copy events between EventMesh and an external |
| system. The runtime treats them as a first-class concern, but the connector |
| processes are **separate**: they run in `eventmesh-connector-runtime` and |
| talk to the data plane over HTTP+CloudEvents. |
| |
| Plugins shipping today cover the common categories: |
| |
| * **Messaging** — Kafka, RocketMQ, RabbitMQ, Pulsar, Redis |
| * **Database** — JDBC, MongoDB, MySQL CDC (via Canal) |
| * **Storage** — S3, file |
| * **HTTP / API** — HTTP, Knative, OpenFunction, Spring |
| * **ChatOps** — DingTalk, Slack, WeChat, WeCom, Lark |
| * **AI** — ChatGPT, MCP (Model Context Protocol) |
| * **Observability** — Prometheus |
| |
| **Where the code lives.** |
| |
| * SPI: `eventmesh-connector-api/` (top-level module since #5328) |
| * Host: `eventmesh-connector-runtime/.../ConnectorManager.java`, |
| `eventmesh-connector-runtime/.../ConnectorAdminServer.java` |
| * Per-connector source: `eventmesh-connector-plugin/eventmesh-connector-<name>/` |
| * Lifecycle: `eventmesh-runtime/.../connector/ConnectorScheduler.java` |
| |
| **Configuration highlights.** |
| |
| ``` |
| eventmesh.connector.runtime.workerThreads = 16 |
| eventmesh.connector.<id>.class = org.apache.eventmesh.connector.file.FileConnector |
| eventmesh.connector.<id>.mode = source-sink |
| eventmesh.connector.<id>.topic = persistent://public/default/file-events |
| ``` |
| |
| **Status.** **Experimental** (capability status table). The runtime |
| itself is end-to-end working and hardened against the data-loss failure |
| class of #5231/#5232/#5233 (#5328), and the SPI now lives in its own |
| `eventmesh-connector-api` module. But of the 23 plugins only four |
| (file/kafka/pulsar/rocketmq) carry unit tests — the rest are template |
| implementations. GA requires tests across the plugin matrix. |
| |
| --- |
| |
| ## 9. Pluggable meta service |
| |
| **What it is.** The L2/L3 state stores are backed by a meta service. |
| Backends currently supported: **Consul**, **Nacos**, **ETCD**, **Zookeeper**. |
| A new meta backend only needs to implement the `MeshStoragePlugin` SPI; the |
| runtime does not care. |
| |
| **Why it matters.** Most enterprise environments already run one of these |
| for service discovery or config. EventMesh can reuse that cluster, so |
| operators do not run a new stateful tier just for EventMesh. |
| |
| **Where the code lives.** |
| |
| * `eventmesh-storage-plugin/eventmesh-storage-nacos/` |
| * `eventmesh-storage-plugin/eventmesh-storage-consul/` |
| * `eventmesh-storage-plugin/eventmesh-storage-etcd/` |
| * `eventmesh-storage-plugin/eventmesh-storage-zookeeper/` |
| * Watch: `eventmesh-runtime/.../cluster/DynamicConfigWatcher.java` |
| |
| --- |
| |
| ## 10. Filtering, transformation, schema |
| |
| **What it is.** A subscriber can attach a **filter expression** at |
| `POST /events/subscribe` so the runtime only delivers events that match |
| (Cel-style expression evaluated server-side). A **transformer** can rewrite |
| the CloudEvent before delivery. Schemas are managed out-of-band by the |
| [EventMesh-catalog](https://github.com/apache/eventmesh-catalog) project |
| using AsyncAPI. |
| |
| **Where the code lives.** |
| |
| * Filter: `eventmesh-runtime/.../protocol/subscribe/filter/` |
| * Transformer: `eventmesh-runtime/.../protocol/subscribe/transform/` |
| * Schema (catalog): `eventmesh-catalog/` |
| |
| --- |
| |
| ## 11. Serverless workflow |
| |
| **What it is.** EventMesh ships a workflow engine |
| ([EventMesh-workflow](https://github.com/apache/eventmesh-workflow)) that |
| runs [Serverless Workflow](https://serverlessworkflow.io/) definitions over |
| events. A workflow can be triggered by an event, listen for follow-up |
| events, and call back into the runtime to publish more events — closing the |
| loop on event orchestration. |
| |
| --- |
| |
| ## 12. Observability and operations |
| |
| **Metrics.** Prometheus exporter on |
| `eventmesh.runtime.metrics.port` (default 9090). Pre-built Grafana |
| dashboards in `eventmesh-examples/observability/`. |
| |
| **Logs.** SLF4J; structured JSON layout optional |
| (`eventmesh.runtime.log.json = true`). |
| |
| **Traces.** `RequestContext.traceContext` propagates W3C trace headers |
| through every plane. OpenTelemetry SDK integration is a single configuration |
| key. |
| |
| **Health & admin.** `/health`, `/metrics`, `/admin/cluster`, and |
| `/admin/connectors` are exposed by the admin server. See |
| [docs/eventmesh-configuration.md](eventmesh-configuration.md#admin) |
| for the full surface. |
| |
| **Runbooks.** [docs/production-readiness.md](production-readiness.md) |
| covers deployment topology, SLOs, and incident response. |
| |
| --- |
| |
| ## 13. Architecture-guard (issue #5305) |
| |
| **What it is.** A separate Gradle module, |
| `eventmesh-architecture-guard`, that hosts ArchUnit rules enforcing the |
| layered architecture. The rules run **twice**: |
| |
| 1. locally on `./gradlew :eventmesh-architecture-guard:check` (30-second |
| feedback loop), and |
| 2. on every PR via `.github/workflows/architecture-guard.yml`. |
| |
| A rule violation **fails the build** in both modes. The 30-second local |
| loop is the key value: it catches layering bugs in the same commit that |
| introduces them, not eight minutes later in CI. |
| |
| **Where the code lives.** |
| |
| * Rules: `eventmesh-architecture-guard/.../guard/ArchitectureRules.java` |
| * Tests: `eventmesh-architecture-guard/.../ArchitectureRulesTest.java` |
| * CI: `.github/workflows/architecture-guard.yml` |
| |
| --- |
| |
| ## 14. Legacy compatibility (TCP / gRPC / OpenMessaging) |
| |
| **What it is.** The original EventMesh wire protocols (TCP + gRPC + |
| OpenMessaging) still work against the new runtime. The new |
| `EventMeshFrame` adaptor (`#5299`) wraps the legacy `MeshMessage` / |
| `OpenMessage` in the same frame type the HTTP path uses, so a single |
| `FilterChain` and a single `SecurityGate` cover both. |
| |
| **Status.** **Legacy-compatible** (capability status table). Existing users |
| are not broken; new users should use the HTTP + CloudEvents path. |
| |
| **Migration.** See |
| [docs/eventmesh-client-guide.md §1.2](eventmesh-client-guide.md) |
| for the drop-in replacement of the legacy `EventMeshClient` with |
| `CloudEventsClient`. |
| |
| --- |
| |
| ## 15. Internationalization |
| |
| The runtime and the docs are English-first. The admin server accepts |
| `Accept-Language` for error messages. The README and most user-facing docs |
| have Chinese translations under `README.zh-CN.md` and module doc files |
| with `.zh-CN.md` suffix. |
| |
| --- |
| |
| ## Feature → module map (at a glance) |
| |
| | Feature | Module | Key file | |
| | --- | --- | --- | |
| | Publish / subscribe | `eventmesh-runtime` | `http/UniHttpServer.java` | |
| | SSE | `eventmesh-runtime` | `protocol/subscribe/SseProcessor.java` | |
| | WebSocket | `eventmesh-runtime` | `http/UniWsServer.java` | |
| | Reliable delivery | `eventmesh-runtime` | `state/DeliveryStateStore.java` | |
| | State control plane | `eventmesh-runtime` + `eventmesh-storage-plugin` | `cluster/`, `state/`, `session/` | |
| | Security gate | `eventmesh-runtime` | `security/gate/SecurityGate.java` | |
| | A2A | `eventmesh-runtime` + `eventmesh-agent` | `a2a/A2AGatewayService.java` | |
| | Storage backends | `eventmesh-storage-plugin/*` | per-backend `MeshStoragePlugin` impl | |
| | Meta service | `eventmesh-storage-plugin/*` (Nacos / Consul / ETCD / ZK) | per-backend impl | |
| | Connectors | `eventmesh-connector-runtime` + `eventmesh-connector-plugin/*` | `ConnectorManager.java` | |
| | Workflow | `EventMesh-workflow` (separate repo) | — | |
| | Schema / catalog | `EventMesh-catalog` (separate repo) | — | |
| | Architecture rules | `eventmesh-architecture-guard` | `guard/ArchitectureRules.java` | |
| | Client SDKs | `eventmesh-sdks` | per-language package | |
| | Observability | `eventmesh-common` | `metrics/`, `trace/` | |
| | Legacy protocols | `eventmesh-runtime` | `protocol/meshmessage/`, `protocol/grpc/` | |