@@ -30,70 +30,79 @@ func (s *Server) GetHostEvents(ctx context.Context, req *gen.GetHostEventsReques
3030 cursor := req .GetCursor ()
3131
3232 for {
33- var wake <- chan struct {}
34- var release func ()
35- if maxWait > 0 {
36- // Subscribe (with the client's kind filter) before Since to avoid
37- // lost wake-ups. Only subscribed kinds wake this waiter, so an
38- // unsubscribed kind (e.g. maintenance) cannot reset the deadline.
39- wake , release = s .hostEvents .Subscribe (subscribe )
33+ resp , err , again := s .getHostEventsOnce (ctx , cursor , clientGen , subscribe , maxWait )
34+ if ! again {
35+ return resp , err
4036 }
37+ // Notified by a subscribed kind: loop and re-check Since.
38+ }
39+ }
4140
42- got := s .hostEvents .Since (cursor , clientGen , subscribe )
43- if got .Reset {
44- if release != nil {
45- release ()
46- }
47- logging .Info ("host_events: GetHostEvents needs_reset" , types .Config ,
48- "cursor" , cursor ,
49- "clientGeneration" , clientGen ,
50- "serverGeneration" , got .Generation ,
51- "nextCursor" , got .NextCursor ,
52- )
53- return s .hostEventsResponse (got , nil , false , true ), nil
54- }
55- if len (got .Events ) > 0 {
56- if release != nil {
57- release ()
58- }
59- logging .Debug ("host_events: GetHostEvents returning events" , types .Config ,
60- "cursor" , cursor ,
61- "count" , len (got .Events ),
62- "nextCursor" , got .NextCursor ,
63- "generation" , got .Generation ,
64- )
65- return s .hostEventsResponse (got , hostEventsToProto (got .Events ), false , false ), nil
66- }
41+ // getHostEventsOnce runs one subscribe → Since → wait cycle. release is deferred
42+ // so every exit path (return or loop-continue via again=true) deregisters the waiter.
43+ func (s * Server ) getHostEventsOnce (
44+ ctx context.Context ,
45+ cursor , clientGen uint64 ,
46+ subscribe []apiconfig.HostEventKind ,
47+ maxWait time.Duration ,
48+ ) (resp * gen.GetHostEventsResponse , err error , again bool ) {
49+ var wake <- chan struct {}
50+ var release func ()
51+ if maxWait > 0 {
52+ // Subscribe (with the client's kind filter) before Since to avoid
53+ // lost wake-ups. Only subscribed kinds wake this waiter, so an
54+ // unsubscribed kind (e.g. maintenance) cannot reset the deadline.
55+ wake , release = s .hostEvents .Subscribe (subscribe )
56+ }
57+ if release != nil {
58+ defer release ()
59+ }
6760
68- if maxWait <= 0 {
69- return s .hostEventsResponse (got , nil , true , false ), nil
70- }
61+ got := s .hostEvents .Since (cursor , clientGen , subscribe )
62+ if got .Reset {
63+ logging .Info ("host_events: GetHostEvents needs_reset" , types .Config ,
64+ "cursor" , cursor ,
65+ "clientGeneration" , clientGen ,
66+ "serverGeneration" , got .Generation ,
67+ "nextCursor" , got .NextCursor ,
68+ )
69+ return s .hostEventsResponse (got , nil , false , true ), nil , false
70+ }
71+ if len (got .Events ) > 0 {
72+ logging .Debug ("host_events: GetHostEvents returning events" , types .Config ,
73+ "cursor" , cursor ,
74+ "count" , len (got .Events ),
75+ "nextCursor" , got .NextCursor ,
76+ "generation" , got .Generation ,
77+ )
78+ return s .hostEventsResponse (got , hostEventsToProto (got .Events ), false , false ), nil , false
79+ }
80+
81+ if maxWait <= 0 {
82+ return s .hostEventsResponse (got , nil , true , false ), nil , false
83+ }
7184
72- logging .Debug ("host_events: GetHostEvents long-poll waiting" , types .Config ,
85+ logging .Debug ("host_events: GetHostEvents long-poll waiting" , types .Config ,
86+ "cursor" , cursor ,
87+ "nextCursor" , got .NextCursor ,
88+ "generation" , got .Generation ,
89+ "maxWait" , maxWait ,
90+ )
91+ outcome , waitErr := longpoll .Wait (ctx , wake , maxWait )
92+ if waitErr != nil {
93+ return nil , status .FromContextError (waitErr ).Err (), false
94+ }
95+ if outcome == longpoll .TimedOut {
96+ got = s .hostEvents .Since (cursor , clientGen , subscribe )
97+ logging .Debug ("host_events: GetHostEvents long-poll timed out" , types .Config ,
7398 "cursor" , cursor ,
7499 "nextCursor" , got .NextCursor ,
75100 "generation" , got .Generation ,
76101 "maxWait" , maxWait ,
77102 )
78- outcome , err := longpoll .Wait (ctx , wake , maxWait )
79- if release != nil {
80- release ()
81- }
82- if err != nil {
83- return nil , status .FromContextError (err ).Err ()
84- }
85- if outcome == longpoll .TimedOut {
86- got = s .hostEvents .Since (cursor , clientGen , subscribe )
87- logging .Debug ("host_events: GetHostEvents long-poll timed out" , types .Config ,
88- "cursor" , cursor ,
89- "nextCursor" , got .NextCursor ,
90- "generation" , got .Generation ,
91- "maxWait" , maxWait ,
92- )
93- return s .hostEventsResponse (got , nil , true , got .Reset ), nil
94- }
95- // Notified by a subscribed kind: loop and re-check Since.
103+ return s .hostEventsResponse (got , nil , true , got .Reset ), nil , false
96104 }
105+ return nil , nil , true
97106}
98107
99108func (s * Server ) hostEventsResponse (got apiconfig.HostEventSince , events []* gen.HostEvent , unchanged , needsReset bool ) * gen.GetHostEventsResponse {
0 commit comments