Reliability expectations and practices for this project.
GET /healthverifies B2 connectivity and returnshealthyordegraded- Health endpoint is always available, even when B2 is down
- HTTP handlers return structured error responses with appropriate status codes
- WebSocket handlers close with structured frames (
{type, code, reason}) the frontend can branch on; close codes live in the application-level 4xxx range - External service failures (B2, OpenAI) are caught and surfaced as 500/503 responses or close frames
- No unhandled exceptions leak stack traces to clients
- Structured JSON logging via Python stdlib
- Every request gets a
request_idfor tracing - Event-aware fields (
event_id,target_lang) are added by the logger formatter when present on theLogRecord - Log levels: ERROR for failures, WARNING for degraded state, INFO for requests
- Request timing middleware logs duration for every request
/metricsendpoint exposes Prometheus-format counters:http_requests_totalhttp_request_duration_secondsevents_started_total/events_ended_totalattendees_joined_totalrealtime_chunks_total
- Reconnect — on transient upstream disconnect, the service layer retries the OpenAI Realtime connection with exponential backoff (1s, 2s, 4s, …, capped at 30s) for up to N attempts before tearing down the broadcast.
- Partial transcript persistence on disconnect —
service.transcripts.persist_chunksruns every 30 seconds of final cues and from the disconnect handler'sfinally:block. Worst-case loss is bounded to one rotation window. - Single-instance state — the
_activebroadcast registry inservice.realtime_sessionis process-local. Multi-instance deployments need to move this into shared state (Redis, Postgres LISTEN/NOTIFY) before they can route attendees that connect to a different replica than the speaker. This is the canonical "do not deploy live interpretation behind a non-sticky load balancer" footgun.
- Events listing returns empty list (not error) when B2 has no
events/prefixes - Glossary listing skips malformed JSON documents and logs a warning rather than failing the whole call
- Audio metadata extraction failures don't block event finalization (manifest carries
duration_ms = null) - Missing
OPENAI_API_KEYsurfaces a startup warning; the rest of the app (events explorer, archive, files, glossary) stays operational - Frontend shows skeleton states while loading, error states on failure
- Lifecycle policy on the
events/prefix to auto-purgeendedevents after N days (e.g. 30) is not configured at scaffold time; see the Backblaze B2 docs on lifecycle rules to wire one up. - For high-traffic events, consider CDN-fronting the source audio + caption files (the URLs are already presignable, but a CDN cache layer reduces direct B2 GETs).
- Railway health checks on
/health - Zero-downtime deploys via rolling updates
- Environment-specific configuration via env vars (no config files in prod)
- Sticky session routing required for the live-interpretation WebSocket pair