TILLCACHE · PUB/SUB
Fan-out, over one stream.
GAPublish a message to a channel and every current subscriber gets it. Delivery runs over Server-Sent Events, so a subscriber is a long-lived HTTP stream — no extra protocol, no socket server to run.
01Publish
publish(channel, message)
ts
import { cache } from './cache'
// Fan a message out to everyone subscribed to the channel:
await cache.publish('presence', { user: 'ada', status: 'online' })publish() delivers to whoever is subscribed right now. It’s fire-and-forget fan-out — for durable, replay-on-restart work that must not be missed, use a queue instead.
02Subscribe
subscribe(channel, onMessage, opts)
subscribe() opens an SSE stream and calls your onMessage for each event. Pass an AbortSignal to close the stream when you’re done:
ts
import { cache } from './cache'
const ac = new AbortController()
cache.subscribe('presence', (message) => {
// message is the payload passed to publish(), deserialized
console.log('presence update', message)
}, { signal: ac.signal })
// Later — stop receiving and close the SSE stream:
ac.abort()Always pass a signal
A subscription is a live connection. Wire an
AbortController to your component or request lifecycle and abort() it on teardown — otherwise streams leak.03Pattern
Tearing down in React
The signal maps cleanly onto an effect cleanup — subscribe on mount, abort on unmount:
tsx
import { useEffect } from 'react'
import { cache } from './cache'
function usePresence(onUpdate: (m: unknown) => void) {
useEffect(() => {
const ac = new AbortController()
cache.subscribe('presence', onUpdate, { signal: ac.signal })
return () => ac.abort() // tear down on unmount
}, [onUpdate])
}04Choosing
Pub/sub vs. a queue
- Pub/sub — one-to-many, ephemeral, delivered to live subscribers. Great for presence, live dashboards, cache-invalidation pings, and UI updates.
- Queues — one message, one worker, durable and retried until acked. Great for jobs that must run, where “nobody was subscribed” isn’t an acceptable outcome.
Back to the TillCache overview, or read up on Backends & vendors to see where a namespace’s channels are anchored.