feat(cdc): add SSE event stream replay#106
Conversation
Greptile SummaryAdds
Confidence Score: 5/5Safe to merge — the subscribe-before-replay ordering, deduplication logic, and overflow handling are all correct, and the tests cover the critical edge cases. The core invariants — subscribe before replay, bounded live buffer with cancel-on-overflow, and seq-based deduplication — are implemented correctly and verified by tests. Context propagation through replay and the live loop is correct, header ordering is right, and the SSE event-name sanitisation guards against frame injection. No data-loss or correctness issues were found on the changed paths. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant EventsController
participant Broadcaster
participant ChangeLog as change_log (cdc.Source)
Client->>EventsController: "GET /api/v1/events?after=N"
EventsController->>Broadcaster: Subscribe(callback → live chan)
Note over EventsController: Headers sent (200, text/event-stream)
EventsController->>ChangeLog: EventsAfter(N, 512)
ChangeLog-->>EventsController: events[N+1..M]
Note over Broadcaster,EventsController: Live events buffered in chan during replay
loop "replay batches until len < 512"
EventsController->>Client: id/event/data frames (seq N+1..M)
EventsController->>ChangeLog: EventsAfter(M, 512)
ChangeLog-->>EventsController: [] (empty)
end
loop live drain (dedup by sentSeq)
EventsController->>Client: "id/event/data frames (seq > M)"
end
alt live chan full
Broadcaster->>EventsController: cancel() context
EventsController-->>Client: connection closed
Client->>EventsController: reconnect with Last-Event-ID
else client disconnect
Client--xEventsController: TCP close
EventsController->>Broadcaster: Unsubscribe
end
Reviews (5): Last reviewed commit: "fix: harden SSE event stream headers" | Re-trigger Greptile |
Two gaps in events_test.go coverage: - TestEventsStreamDeduplicatesLiveEventOverlappingReplay: a live event whose seq falls within the already-replayed range must be silently dropped by writeSSEEvent so the client sees each seq exactly once. Publishes seq=5 (duplicate of replay) and seq=6 (new) into the live buffer before replay returns; asserts the client receives [5,6], not [5,5,6]. - TestEventsStreamParsesLastEventIDHeader: Last-Event-ID header must be used as the replay cursor when the after query param is absent. Source returns after+1, so receiving seq=8 proves the header was parsed as 7. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Regenerated with npm run api after merging the OpenAPI spec generation tooling from main. Adds the streamEvents operation and its after cursor parameter to the TypeScript API types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds GET /api/v1/events for CDC SSE streaming with durable replay from change_log. Keeps cdc.Broadcaster live-only; the HTTP stream layer subscribes before replay, drains buffered live events, and dedupes by seq. Supports after and Last-Event-ID cursors, documents text/event-stream in OpenAPI, and adds tests for replay/live handoff plus invalid after. Tests: go test ./...