Architecture

How RevenProx works

Summary

RevenProx holds long-lived SSE connections at the edge and synchronizes state across a fully distributed, brokerless NNG mesh. Instances agree on which topics exist and where subscribers live using bloom filters, merkle trees, and vector clocks; events are routed to subscribers by UUID topic; and clients are authenticated with webhook-based JWT verification that caches results and trips a circuit breaker to protect the auth upstream. Written in Zig, it holds millions of idle-but-open connections at low, predictable per-connection memory.

Publisherpublish(topic)rp-1rp-2rp-3Brokerless NNG meshclients · topic Aclients · topic B10M+ SSE conns

One publish, routed by UUID topic, fanned out to the right subscribers — no central broker.

Data path

End to end, one event

From a client opening a stream to that client receiving a published event.

Connect

A client opens a long-lived SSE request (e.g. GET /events/<topic>) against any proxy instance and passes a JWT.

Authenticate

The instance verifies the JWT via a webhook to your auth service, caching the result so repeat connects do not re-hit the upstream.

Subscribe

The connection is registered against a UUID topic. Membership propagates across the mesh so every instance knows a subscriber exists.

Publish

An event published to a topic — on any instance — is relayed across the NNG mesh to exactly the instances holding subscribers for that topic.

Deliver

Each instance writes the event down its local matching SSE connections. No event travels to an instance that has no subscribers for the topic.

The brokerless NNG mesh

The defining decision in RevenProx is that there is no central message broker. A broker is the classic scaling ceiling for pub/sub: every message and every subscription passes through it, so it becomes the thing you must over-provision, license, and page someone about at 3am. RevenProx removes it entirely. The proxy instances connect to one another directly overNNG (nanomsg-next-gen) to form a peer-to-peer mesh. Any instance can accept a publish and get it to every subscriber across the fleet, so there is no single coordinator to bottleneck — you add throughput by adding instances.

State synchronization: bloom + merkle + vector clocks

A brokerless mesh needs every instance to agree on distributed state — which topics exist and which instances currently hold subscribers for them — without a central registry. RevenProx does this with three complementary primitives:

  • Bloom filters give each instance a compact, probabilistic summary of the topics it holds subscribers for. Peers exchange these to cheaply answer "could you have subscribers for this topic?" and skip forwarding events to instances that definitely do not — keeping fan-out targeted instead of flooding the mesh.
  • Merkle trees let two instances compare their view of shared state by exchanging hashes rather than the full state. Matching root hashes mean "we already agree"; a mismatch lets them walk the tree to find exactly which branches diverged, so reconciliation transfers only the diff.
  • Vector clocks order updates across instances without a global clock. When the same topic's membership changes on different nodes, vector clocks establish causal ordering and detect concurrent updates, so the mesh converges on a consistent view instead of races producing contradictory state.

Together these make state sync gossip-friendly and bandwidth-cheap: instances mostly confirm they already agree, and only exchange real data when something has actually changed.

rp-1rp-2rp-3rp-4rp-5rp-6bloom filters · merkle trees · vector clocks — no coordinator

Every instance peers directly. State stays consistent with bloom filters, merkle trees, and vector clocks.

UUID topic-based routing

Every stream is a UUID topic. Clients subscribe to a topic; publishers publish to a topic; the mesh routes by topic. Using UUIDs gives an effectively unlimited, collision-free topic space — you can mint a topic per user, per session, per document, or per conversation without coordination. Because routing is per-topic, an event only reaches the clients that subscribed to it: targeted fan-out, not broadcast-to-everyone.

Authentication: webhook JWT + cache + circuit breaker

RevenProx authenticates connections with JWTs, but verification iswebhook-based — the proxy calls out to your auth service to validate a token rather than embedding your auth logic. Two mechanisms keep that from becoming a liability at scale:

  • Caching. Verification results are cached, so a burst of reconnects for an already-seen token does not translate into a burst of calls to your auth service.
  • Circuit breaker. If the auth upstream starts failing or slowing down, the circuit breaker trips and stops hammering it, protecting a degraded dependency from a thundering herd instead of amplifying the outage.

Memory model: why Zig

When you hold millions of connections that are mostly idle, cost is governed byper-connection memory, not CPU. RevenProx is written in Zig: no garbage collector, no heavyweight runtime, and manual, predictable memory layout. That keeps per-connection overhead small and — just as importantly — predictable, so a node's capacity is a number you can plan a fleet around rather than a GC-pause lottery. This is the property that makes the 10M+ concurrent, 100+ instance target reachable.

Memory, not CPU, is the budget. With millions of mostly-idle streams, a node's capacity is governed by predictable per-connection memory — which is exactly why RevenProx is written in Zig rather than a GC language.

Deployment shape

RevenProx builds to a single static binary with Zig and isself-hosted on your own infrastructure — no managed control plane. Instances discover one another and form the NNG mesh; you scale by running more of them. Docker and Kubernetes deployment guides are provided in the documentation.

Full documentationSource on GitHub →