Skip to content

0029. The SSE endpoint wakes on a cache key, not Valkey pub/sub

Generated from docs/decisions/0029-sse-wake-without-pubsub.md

  • Status: Accepted (2026-10-09)
  • Date: 2026-10-09

ADR 0011 planned that the SSE endpoint wakes on a Valkey pub/sub ping with a 500 ms polling fallback. A PHP subscriber blocks the worker inside SUBSCRIBE and cannot also enforce the 25 s connection cap or notice a closed client without extra machinery.

EventLog::append() writes the new event id to the cache key course_builder:last_event:<session> (Valkey in the stack, per-tenant prefix). The stream loop reads that key every COURSE_BUILDER_SSE_POLL_MS (500 ms) and queries the events table only when it changed. Without a cache the loop polls the table. Connections still close after COURSE_BUILDER_SSE_SECONDS (25 s). The separate FPM pool for the events route stays an operations step (Caddy route to a small pool).

  • Good: no subscriber process, works with any cache store, the same code under Octane.
  • Bad: up to 500 ms latency per event and one cache read per tick per open stream.