Resolve WebSocket event target open questions, add subscription control protocol
- Resolve OQ1: WS server accepts raw WebSocket instances via addConnection/removeConnection (framework-agnostic, not coupled to Hono/Express/Bun/Deno) - Resolve OQ2: Backpressure handled by disconnecting slow consumers at configurable threshold (default 1MB), with onBackpressure callback for observability - Resolve OQ3: Topic-based fan-out with subscription tracking instead of broadcast-all; spokes send __subscribe/__unsubscribe control events; direct messaging via 'direct:' topic pattern Add ADR-003 for subscription control protocol decision. Update all fan-out adapters (WS server, Iroh hub) and spoke adapters (WS client, Iroh spoke) with subscription tracking/forwarding. Fix routing key ambiguity (full topic string, not event type alone). Add error handling, composition, and reserved type sections. Clarify Worker as symmetric-only.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-07
|
||||
last_updated: 2026-05-08
|
||||
---
|
||||
|
||||
# Event Target Adapters
|
||||
@@ -21,11 +21,41 @@ Every adapter must implement:
|
||||
|
||||
Adapters come in two shapes:
|
||||
|
||||
- **Symmetric** (single connection) — wraps one connection. Same interface on both sides. Examples: Redis, Iroh spoke, WebSocket client, Worker main-thread.
|
||||
- **Fan-out** (multi-connection) — manages multiple connections. `dispatchEvent` sends to all; `addEventListener` aggregates from all. Examples: WebSocket server, Iroh hub, Worker pool manager.
|
||||
- **Symmetric** (single connection) — wraps one connection. Same interface on both sides. Examples: Redis, Iroh spoke, WebSocket client, Worker.
|
||||
- **Fan-out** (multi-connection) — manages multiple connections. `dispatchEvent` sends only to connections subscribed to the event type (topic-based fan-out); `addEventListener` aggregates from all. Examples: WebSocket server, Iroh hub.
|
||||
|
||||
Worker is a symmetric adapter (point-to-point). A Worker pool manager would be a fan-out concern, but that belongs in `@alkdev/operations`, not in this package.
|
||||
|
||||
The `createPubSub` layer is topology-agnostic. A hub composes multiple adapters and uses operators to combine streams — this is downstream application logic, not a package boundary.
|
||||
|
||||
## Composing Adapters
|
||||
|
||||
Adapters compose at the `createPubSub` level, not by nesting adapters. A common pattern:
|
||||
|
||||
```
|
||||
Client (WS spoke) → Server (WS hub) → Redis → Other servers
|
||||
```
|
||||
|
||||
In this topology:
|
||||
- The WS hub adapter manages spoke connections with topic-based fan-out
|
||||
- The hub's `createPubSub` instance also has a Redis event target for cross-server communication
|
||||
- Subscription state at the hub level aggregates: when a spoke subscribes to topic `X`, the hub may also subscribe to `X` on Redis (if no other spoke is already subscribed)
|
||||
|
||||
This composition is handled by `createPubSub` bridging multiple event targets, not by adapters wrapping each other. The fan-out adapter's subscription tracking is local to its connected spokes; upstream subscriptions are a `createPubSub` concern.
|
||||
|
||||
## Subscription Control Protocol
|
||||
|
||||
Fan-out adapters must know which connections are interested in which topics. Symmetric adapters that connect to a fan-out adapter must declare their subscriptions. This is done through **control events** — `EventEnvelope` messages with reserved `__`-prefixed types:
|
||||
|
||||
- `__subscribe` — sent when a spoke adds the first listener for a topic
|
||||
- `__unsubscribe` — sent when a spoke removes the last listener for a topic
|
||||
|
||||
The `id` field in control events is the empty string (`""`) by convention. Control events use the `topic` field in their payload for routing instead. Control events are handled internally by adapters and never dispatched to user-facing listeners. Event types starting with `__` are reserved — user code must not define event types with this prefix.
|
||||
|
||||
See [ADR-003](decisions/003-subscription-control-protocol.md).
|
||||
|
||||
This is analogous to Redis's `SUBSCRIBE`/`UNSUBSCRIBE` commands — control messages share the same wire format and connection as data.
|
||||
|
||||
## Adapter Docs
|
||||
|
||||
| Adapter | Import | Status |
|
||||
|
||||
Reference in New Issue
Block a user