@@ -122,6 +122,7 @@ func (h *UnconfirmedMessageHandlerImpl) ObserveSending(resourceID string) {
122122
123123// HandleACK is called when an ACK is received for a resource.
124124func (h * UnconfirmedMessageHandlerImpl ) HandleACK (resourceID string ) {
125+ var onAckCallback func (string )
125126 concurrency .WithLock (& h .mu , func () {
126127 // Check if handler is stopped before any operations
127128 if h .ctx .Err () != nil {
@@ -133,23 +134,29 @@ func (h *UnconfirmedMessageHandlerImpl) HandleACK(resourceID string) {
133134 if state .timer != nil {
134135 state .timer .Stop ()
135136 }
136- state .retry = 0
137- state .numUnackedSendings = 0
137+ delete (h .resources , resourceID )
138138 log .Debugf ("[%s] Received ACK for resource %s" , h .handlerName , resourceID )
139139 } else {
140140 log .Debugf ("[%s] Received ACK for unknown resource %s" , h .handlerName , resourceID )
141141 }
142+ // Check callback inside the lock.
143+ if h .onACK != nil {
144+ onAckCallback = h .onACK
145+ }
142146 })
143147
144- // Invoke callback outside lock
145- if h . onACK != nil {
146- h . onACK (resourceID )
148+ // Invoke callback outside the lock to avoid potentially long-running operations inside the lock.
149+ if onAckCallback != nil {
150+ onAckCallback (resourceID )
147151 }
148152}
149153
150154// HandleNACK is called when a NACK is received for a resource.
151155// It just logs - the existing timer will handle retry based on normal backoff.
152156func (h * UnconfirmedMessageHandlerImpl ) HandleNACK (resourceID string ) {
157+ // HandleNACK is currently a no-op and has the same behavior as not reciving any [N]ACK message.
158+ // This is intentional as we want to keep retrying until Central is able to process the message.
159+ // This will change in the future where NACK can be treated as a signal to slow down retries.
153160 log .Debugf ("[%s] Received NACK for resource %s. Message will be resent." , h .handlerName , resourceID )
154161}
155162
@@ -202,11 +209,14 @@ func (h *UnconfirmedMessageHandlerImpl) onTimerFired(resourceID string) {
202209 return
203210 case h .retryCommandCh <- resourceID :
204211 default :
212+ // If the channel is full or the consumer goroutine is busy, we assume that currently a
213+ // transimssion of a message is in progress. This means, that we do not need to enqueue
214+ // another message immediately afterwards. Thus, we drop the retry signal and log a warning.
205215 log .Warnf ("[%s] Retry channel full, dropping retry signal for %s" , h .handlerName , resourceID )
206216 }
207217}
208218
209- // calculateNextInterval returns the next retry interval with exponential backoff.
219+ // calculateNextInterval returns the next retry interval with linear backoff.
210220func (h * UnconfirmedMessageHandlerImpl ) calculateNextInterval (retry int32 ) time.Duration {
211221 if h .baseInterval <= 0 {
212222 return defaultBaseInterval
0 commit comments