API-74Recommended
Deliver events through a shared channel
When more than one server holds connections, publish every event to a shared channel. Each server then delivers it to the clients connected to it.
How to do it
A client is connected to one server, but the change that concerns it can happen on any server. Publish each event to a shared channel, such as Redis or Valkey pub/sub, NATS or PostgreSQL LISTEN and NOTIFY. Every server subscribes and forwards events to its own clients. Publish only after the change is committed, through an outbox, so clients never see a change that was rolled back. Plain pub/sub drops messages while a server is down, so keep the event IDs from reconnect and resume to fill the gap.
Examples
JavaScript example
import { createClient } from 'redis';
const subscriber = createClient({ url: process.env.REDIS_URL });
await subscriber.connect();
await subscriber.subscribe('shop-events', raw => {
const event = JSON.parse(raw);
for (const socket of socketsByShop.get(event.shopId) ?? []) socket.send(raw);
});
Python example
import json
import redis.asyncio as redis
async def forward_events():
pubsub = redis.from_url(REDIS_URL).pubsub()
await pubsub.subscribe("shop-events")
async for message in pubsub.listen():
if message["type"] != "message":
continue
event = json.loads(message["data"])
for socket in sockets_by_shop.get(event["shopId"], []):
await socket.send(message["data"])
How to check
Run two server instances. Connect a test client to the first and change its order through the second. The client receives the event within 2 seconds.
Sources
Related rules
- Send side effects through an outbox in Data
- Reconnect with backoff and resume from the last event in API design
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/api-design/live-connections/shared-pubsub">Agent Wranglers API design playbook</a>. In code you write, add a comment next to it with the same link.