@@ -319,7 +319,7 @@ func (s *subscriber) addPendingReceipt(receipt Receipt, filterer Filterer) {
319319func (s * subscriber ) retryPendingReceipts (ctx context.Context ) {
320320 s .retryMu .Lock ()
321321
322- // Collect receipts that are due for retry
322+ // Create a snapshot of receipts that are due for retry
323323 var toRetry []pendingReceipt
324324 now := time .Now ()
325325
@@ -336,7 +336,7 @@ func (s *subscriber) retryPendingReceipts(ctx context.Context) {
336336
337337 s .listener .log .Info (fmt .Sprintf ("ethreceipts: retrying %d pending receipts" , len (toRetry )))
338338
339- // Process retries concurrently with bounded parallelism
339+ // Collect receipts that are due for retry
340340 sem := make (chan struct {}, maxConcurrentReceiptRetries )
341341 var wg sync.WaitGroup
342342
@@ -359,46 +359,44 @@ func (s *subscriber) retryPendingReceipts(ctx context.Context) {
359359 s .retryMu .Lock ()
360360 defer s .retryMu .Unlock ()
361361
362- if err != nil {
362+ currentPending , exists := s .pendingReceipts [txHash ]
363+ if ! exists {
364+ s .listener .log .Warn ("Pending receipt no longer exists in map, skipping" , "txHash" , txHash .String ())
365+ return
366+ }
363367
368+ if err != nil {
364369 if errors .Is (err , ethereum .NotFound ) {
365370 // Transaction genuinely doesn't exist - remove from queue
366371 delete (s .pendingReceipts , txHash )
367- s .listener .log .Debug ("Receipt not found after retry, removing from queue" ,
368- "txHash" , txHash .String ())
372+ s .listener .log .Debug ("Receipt not found after retry, removing from queue" , "txHash" , txHash .String ())
369373 return
370374 }
371375
372- // Provider error - update retry state
373- p .attempts ++
374-
375- // Check if max attempts reached
376- if p .attempts >= maxReceiptRetryAttempts {
377- // This will definitely remove the pending receipt, if it arrives
378- // later subscribers won't get notified.
376+ // Provider error - update retry state from the current state in the map
377+ currentPending .attempts ++
378+ if currentPending .attempts >= maxReceiptRetryAttempts {
379379 delete (s .pendingReceipts , txHash )
380380 s .listener .log .Error ("Failed to fetch receipt after max retries" ,
381381 "txHash" , txHash .String (),
382- "attempts" , p .attempts ,
382+ "attempts" , currentPending .attempts ,
383383 "error" , err )
384-
385384 // TODO: perhaps we should close the subscription here as we failed
386385 // to deliver a receipt after many attempts?
387386 return
388387 }
389388
390389 // Exponential backoff for next retry
391- backoff := time .Duration (1 << uint (p .attempts )) * time .Second
390+ backoff := time .Duration (1 << uint (currentPending .attempts )) * time .Second
392391 if backoff > maxWaitBetweenRetries {
393392 backoff = maxWaitBetweenRetries
394393 }
395-
396- p .nextRetryAt = time .Now ().Add (backoff )
397- s .pendingReceipts [txHash ] = p
394+ currentPending .nextRetryAt = time .Now ().Add (backoff )
395+ s .pendingReceipts [txHash ] = currentPending
398396
399397 s .listener .log .Debug ("Receipt fetch failed, will retry" ,
400398 "txHash" , txHash .String (),
401- "attempt" , p .attempts ,
399+ "attempt" , currentPending .attempts ,
402400 "nextRetryIn" , backoff ,
403401 )
404402 return
@@ -433,7 +431,7 @@ func (s *subscriber) retryPendingReceipts(ctx context.Context) {
433431
434432 s .listener .log .Info ("Successfully fetched receipt after retry" ,
435433 "txHash" , txHash .String (),
436- "attempts" , p .attempts )
434+ "attempts" , currentPending .attempts )
437435 }(pending )
438436 }
439437
0 commit comments