Skip to content

[Control Plane] Memory events SSE handler defers header flush, causing client hangs #358

@santoshkumarradha

Description

@santoshkumarradha

Summary

MemoryEventsHandler.SSEHandler does not flush response headers until it writes its first event. This means an SSE client connecting with a scope/pattern filter that has no immediately-matching events will hang on http.Client.Do until either:

  1. A matching event arrives (eventually flushes headers via the first c.SSEvent + c.Writer.Flush), or
  2. The client disconnects, which the handler currently detects via the deprecated c.Writer.CloseNotify()

This produces a flaky CI failure for TestMemoryEventsHandler_SSEHappyPathHonorsScopeFilter (currently t.Skip'd in PR #352) and is also a real-world UX issue: any UI that opens an SSE connection appears stuck until the first event arrives.

Where

  • File: control-plane/internal/handlers/memory_events.go
  • Function: MemoryEventsHandler.SSEHandler
  • Skipped test: control-plane/internal/handlers/memory_events_test.go::TestMemoryEventsHandler_SSEHappyPathHonorsScopeFilter (skip message: flaky in CI: SSE handler defers header flush; covered by WS + cleanup tests)

Expected behavior

Standard SSE handler shape:

  1. Set headers (Content-Type: text/event-stream, etc.)
  2. Call c.Writer.WriteHeader(http.StatusOK) and c.Writer.Flush() immediately so the client receives headers and can begin reading the body
  3. Optionally write a : connected\n\n comment frame as a heartbeat / keepalive marker
  4. Then enter the event loop

Replacing c.Writer.CloseNotify() with c.Request.Context().Done() is also worth doing — CloseNotifier is deprecated in net/http and behaves inconsistently across httptest vs production servers.

Acceptance criteria

  • SSEHandler flushes headers (and ideally a comment frame) before entering the event loop
  • SSEHandler uses c.Request.Context().Done() instead of CloseNotify() for disconnect detection
  • The skipped test in memory_events_test.go::TestMemoryEventsHandler_SSEHappyPathHonorsScopeFilter is unskipped and passes deterministically (locally and in CI)
  • No regression in the other memory-events tests (WS happy path, invalid-pattern cleanup, backpressure, upgrade rejection)

Discovered via

PR #352 (test coverage improvements). Added during the SSE end-to-end test pass; the test was racy in CI and is currently t.Skip'd pending this fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai-friendlyWell-documented task suitable for AI-assisted developmentarea:control-planeControl plane server functionalityarea:memoryMemory system functionalitybugSomething isn't workinghelp wantedExtra attention is neededtestsUnit test improvements and coverage

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions