This is an automated email from the ASF dual-hosted git repository.

wilfred-s pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-core.git


The following commit(s) were added to refs/heads/master by this push:
     new b92cd121 [YUNIKORN-3364] Fix event stream history replay blocking 
forever on disconnect (#1133)
b92cd121 is described below

commit b92cd1215feee0fd3319600ec46a6e219605580d
Author: PoiBlackTea <[email protected]>
AuthorDate: Wed Sep 2 14:09:16 2026 +0200

    [YUNIKORN-3364] Fix event stream history replay blocking forever on 
disconnect (#1133)
    
    EventStreaming.CreateEventStream replayed historical events with a bare
    blocking send (consumer <- event) outside the forwarder's select loop.
    When a client requested non-zero history and disconnected before the stream
    opened, or when history events exceeded channel buffer size (1000), the send
    blocked indefinitely. Since the goroutine had not yet entered the select 
loop,
    neither stop channel (stop or e.stopCh) could be reached, causing goroutine
    and memory leaks.
    
    Wrap the history-replay send in a select block with e.stopCh and stop cases,
    and add a unit test to verify early disconnect during history replay.
    
    Closes: #1133
    
    Signed-off-by: Wilfred Spiegelenburg <[email protected]>
---
 pkg/events/event_streaming.go      | 10 +++++++++-
 pkg/events/event_streaming_test.go | 15 +++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/pkg/events/event_streaming.go b/pkg/events/event_streaming.go
index 59daac50..0aabef31 100644
--- a/pkg/events/event_streaming.go
+++ b/pkg/events/event_streaming.go
@@ -106,7 +106,15 @@ func (e *EventStreaming) CreateEventStream(name string, 
count uint64) *EventStre
                // map, so "local" will also contain the new event.
                seen := make(map[*si.EventRecord]bool)
                for _, event := range history {
-                       consumer <- event
+                       select {
+                       case consumer <- event:
+                       case <-e.stopCh:
+                               close(consumer)
+                               return
+                       case <-stop:
+                               close(consumer)
+                               return
+                       }
                        seen[event] = true
                }
                for {
diff --git a/pkg/events/event_streaming_test.go 
b/pkg/events/event_streaming_test.go
index 498f540e..dcb5af75 100644
--- a/pkg/events/event_streaming_test.go
+++ b/pkg/events/event_streaming_test.go
@@ -162,6 +162,21 @@ func TestGetEventStreams(t *testing.T) {
        assert.Equal(t, 0, len(streaming.eventStreams))
 }
 
+func TestEventStreaming_HistoryReplay_SlowConsumer(t *testing.T) {
+       buffer := newEventRingBuffer(1500)
+       for i := 0; i < 1500; i++ {
+               buffer.Add(&si.EventRecord{TimestampNano: int64(i)})
+       }
+       streaming := NewEventStreaming(buffer)
+       defer streaming.Close()
+
+       // requesting more historical events than defaultChannelBufSize (1000) 
and disconnecting
+       es := streaming.CreateEventStream("test", 1500)
+       streaming.RemoveEventStream(es)
+
+       assert.Equal(t, 0, len(streaming.eventStreams))
+}
+
 func receive(t *testing.T, input <-chan *si.EventRecord) *si.EventRecord {
        select {
        case event := <-input:


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to