---
title: "Deliver events through a shared channel · Agent Wranglers"
url: https://agentwranglers.se/playbook/api-design/live-connections/shared-pubsub
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Deliver events through a shared channel

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Live connections](https://agentwranglers.se/playbook/api-design/live-connections.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- ID: API-74
- Level: Recommended
- Chapter: [Live connections](https://agentwranglers.se/playbook/api-design/live-connections)
- Rule: 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.
- Applies when: The project runs its own servers, virtual machines or containers.
- How: 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](https://agentwranglers.se/playbook/data/transactions-and-concurrency/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](https://agentwranglers.se/playbook/api-design/live-connections/reconnect-and-resume) to fill the gap.
- 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.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
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

```python
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"])
```

## Sources

- [Redis pub/sub delivery semantics](https://redis.io/docs/latest/develop/pubsub/)

## Related rules

- [Send side effects through an outbox](https://agentwranglers.se/playbook/data/transactions-and-concurrency/outbox) in Data
- [Reconnect with backoff and resume from the last event](https://agentwranglers.se/playbook/api-design/live-connections/reconnect-and-resume) in API design

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/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.

- Previous: [Limit the connections and messages of each client](https://agentwranglers.se/playbook/api-design/live-connections/connection-limits)
- [Live connections](https://agentwranglers.se/playbook/api-design/live-connections)
