- Create docs/architecture/event-targets/ with individual specs: in-process, redis, websocket-client, websocket-server, worker, iroh-spoke, iroh-hub - Update event-targets.md to serve as index with topology model (symmetric vs fan-out) and adapter status table - Update architecture.md index to reference new directory
2.6 KiB
2.6 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-05-07 |
Redis Event Target
Import: @alkdev/pubsub/event-target-redis
Peer dep: ioredis@^5.0.0 (optional)
Status: Implemented. Needs tests.
Adapted from @graphql-yoga/redis-event-target (MIT).
createRedisEventTarget
function createRedisEventTarget<TEvent extends TypedEvent>(
args: CreateRedisEventTargetArgs,
): TypedEventTarget<TEvent>;
CreateRedisEventTargetArgs
| Field | Type | Required | Description |
|---|---|---|---|
publishClient |
Redis | Cluster |
Yes | ioredis client for publishing. Can share a connection. |
subscribeClient |
Redis | Cluster |
Yes | ioredis client for subscribing. Must be dedicated — Redis requires subscriber connections to only receive messages. |
serializer |
{ stringify, parse } |
No | Custom serializer. Defaults to JSON. |
How It Works
dispatchEvent→publishClient.publish(event.type, serializer.stringify(event.detail))addEventListener→subscribeClient.subscribe(topic), track callbacks per topicremoveEventListener→ remove callback; if no callbacks remain for topic,subscribeClient.unsubscribe(topic)- On message: deserializes with
serializer.parse, reconstructsCustomEvent(channel, { detail: envelope })
The detail of the CustomEvent dispatched to local listeners is the full EventEnvelope object ({ type, id, payload }).
Channel Naming
Currently uses the topic string directly as the Redis channel name (e.g., call.responded:uuid-123). Should support a configurable prefix: createRedisEventTarget({ ..., prefix: "alk:events:" }).
Limitations (Current)
- No error handling — connection failures, reconnection, and message parse errors are not handled
- No channel prefix — raw event types as channel names risk collision in shared Redis instances
- No unsubscribe cleanup on client disconnect — if the subscribe client disconnects, registered callbacks remain in the map but will never fire
Test Coverage
No tests yet. Need:
- Publish path — dispatchEvent sends to Redis with correct channel and serialized envelope
- Subscribe path — addEventListener subscribes to Redis, onMessage dispatches to local listeners
- Unsubscribe — removeEventListener unsubscribes from Redis when no listeners remain for a topic
- Topic scoping — type:id topics are correctly formed
- Envelope serialization — full
{ type, id, payload }round-trips through JSON - Multiple listeners — multiple listeners on same topic, single Redis subscribe
- Error propagation — what happens on connection failure