@@ -728,58 +728,64 @@ func (a *FlowableActivity) normalizeLoop(
728728 defer normalizeWaiting .Store (false )
729729
730730 for {
731- normalizeWaiting .Store (true )
732- ch := normalizeRequests .Wait ()
733- if ch == nil {
734- logger .Info ("[normalize-loop] lastChan closed" )
735- return
736- }
737- select {
738- case <- syncDone :
739- logger .Info ("[normalize-loop] syncDone closed" )
740- return
741- case <- ctx .Done ():
742- logger .Info ("[normalize-loop] context closed" )
743- return
744- case <- ch :
745- reqBatchID := normalizeRequests .Load ()
746- lastNormalizedBatchID := normalizingBatchID .Load ()
747- if reqBatchID <= lastNormalizedBatchID {
731+ // Check for pending work before waiting on the channel.
732+ // This avoids a race where Update() replaces the channel while we're
733+ // processing, causing Wait() to return the new (unclosed) channel
734+ // and missing the signal entirely until the next Update.
735+ reqBatchID := normalizeRequests .Load ()
736+ lastNormalizedBatchID := normalizingBatchID .Load ()
737+ if reqBatchID <= lastNormalizedBatchID {
738+ normalizeWaiting .Store (true )
739+ ch := normalizeRequests .Wait ()
740+ if ch == nil {
741+ logger .Info ("[normalize-loop] lastChan closed" )
742+ return
743+ }
744+ select {
745+ case <- syncDone :
746+ logger .Info ("[normalize-loop] syncDone closed" )
747+ return
748+ case <- ctx .Done ():
749+ logger .Info ("[normalize-loop] context closed" )
750+ return
751+ case <- ch :
748752 continue
749753 }
750- retryInterval := time .Minute
751- retryLoop:
752- for {
753- normalizingBatchID .Store (reqBatchID )
754- if err := a .startNormalize (ctx , config , reqBatchID , normalizeResponses ); err != nil {
755- _ = a .Alerter .LogFlowError (ctx , config .FlowJobName , err )
756- for {
757- // update req to latest normalize request & retry
758- select {
759- case <- syncDone :
760- logger .Info ("[normalize-loop] syncDone closed before retry" )
761- return
762- case <- ctx .Done ():
763- logger .Info ("[normalize-loop] context closed before retry" )
764- return
765- default :
766- time .Sleep (retryInterval )
767- retryInterval = min (retryInterval * 2 , 5 * time .Minute )
768- // record the last normalized batch ID even if retry fails to populate metrics consistently
769- a .OtelManager .Metrics .LastNormalizedBatchIdGauge .Record (
770- ctx , lastNormalizedBatchID , metric .WithAttributeSet (attribute .NewSet (
771- attribute .String (otel_metrics .FlowNameKey , config .FlowJobName ),
772- )))
773- reqBatchID = normalizeRequests .Load ()
774- continue retryLoop
775- }
754+ }
755+ normalizeWaiting .Store (false )
756+
757+ retryInterval := time .Minute
758+ retryLoop:
759+ for {
760+ normalizingBatchID .Store (reqBatchID )
761+ if err := a .startNormalize (ctx , config , reqBatchID , normalizeResponses ); err != nil {
762+ _ = a .Alerter .LogFlowError (ctx , config .FlowJobName , err )
763+ for {
764+ // update req to latest normalize request & retry
765+ select {
766+ case <- syncDone :
767+ logger .Info ("[normalize-loop] syncDone closed before retry" )
768+ return
769+ case <- ctx .Done ():
770+ logger .Info ("[normalize-loop] context closed before retry" )
771+ return
772+ default :
773+ time .Sleep (retryInterval )
774+ retryInterval = min (retryInterval * 2 , 5 * time .Minute )
775+ // record the last normalized batch ID even if retry fails to populate metrics consistently
776+ a .OtelManager .Metrics .LastNormalizedBatchIdGauge .Record (
777+ ctx , lastNormalizedBatchID , metric .WithAttributeSet (attribute .NewSet (
778+ attribute .String (otel_metrics .FlowNameKey , config .FlowJobName ),
779+ )))
780+ reqBatchID = normalizeRequests .Load ()
781+ continue retryLoop
776782 }
777783 }
778- a .OtelManager .Metrics .LastNormalizedBatchIdGauge .Record (ctx , reqBatchID , metric .WithAttributeSet (attribute .NewSet (
779- attribute .String (otel_metrics .FlowNameKey , config .FlowJobName ),
780- )))
781- break
782784 }
785+ a .OtelManager .Metrics .LastNormalizedBatchIdGauge .Record (ctx , reqBatchID , metric .WithAttributeSet (attribute .NewSet (
786+ attribute .String (otel_metrics .FlowNameKey , config .FlowJobName ),
787+ )))
788+ break
783789 }
784790 }
785791}
0 commit comments