@@ -28,9 +28,9 @@ type eventStream struct {
2828
2929 pingPayload []byte
3030
31- initiated atomic.Bool
32-
31+ initiated atomic.Bool
3332 initiateOnce sync.Once
33+
3434 closeOnce sync.Once
3535 shutdownOnce sync.Once
3636 eventsCh chan event
@@ -79,14 +79,22 @@ func (s *eventStream) start(w http.ResponseWriter, r *http.Request) {
7979 return
8080 case ev , open = <- s .eventsCh : // Once closed, the buffered channel will drain all buffered values before showing as closed.
8181 if ! open {
82+ s .logger .Debug (ctx , "events channel closed" )
8283 return
8384 }
8485
8586 // Initiate the stream once the first event is received.
8687 s .initiateOnce .Do (func () {
8788 s .initiated .Store (true )
89+ s .logger .Debug (ctx , "stream initiated" )
8890
8991 // Send headers for Server-Sent Event stream.
92+ //
93+ // We only send these once an event is processed because an error can occur in the upstream
94+ // request prior to the stream starting, in which case the SSE headers are inappropriate to
95+ // send to the client.
96+ //
97+ // See use of isStreaming().
9098 w .Header ().Set ("Content-Type" , "text/event-stream" )
9199 w .Header ().Set ("Cache-Control" , "no-cache" )
92100 w .Header ().Set ("Connection" , "keep-alive" )
@@ -185,8 +193,10 @@ func (s *eventStream) Shutdown(shutdownCtx context.Context) error {
185193 return err
186194}
187195
188- func (s * eventStream ) hasInitiated () bool {
189- return s .initiated .Load ()
196+ // isStreaming checks if the stream has been initiated, or
197+ // when events are buffered which - when processed - will initiate the stream.
198+ func (s * eventStream ) isStreaming () bool {
199+ return s .initiated .Load () || len (s .eventsCh ) > 0
190200}
191201
192202// isConnError checks if an error is related to client disconnection or context cancellation.
0 commit comments