(resultCh <-chan refreshResult)
| 502 | } |
| 503 | |
| 504 | func (c *counterInt64) continueAsyncRefresh(resultCh <-chan refreshResult) { |
| 505 | go func() { |
| 506 | // Bound the helper's lifetime. The paired refresh worker is capped by |
| 507 | // fnCtx (fallbackTimeout), but if a downstream call ignores its context |
| 508 | // the worker may never send and this goroutine would leak permanently. |
| 509 | // Cap at fallbackTimeout + a small buffer; drop the eventual value in |
| 510 | // the pathological case — the next TryUpdateIfStale will refresh again. |
| 511 | timer := time.NewTimer(c.registry.fallbackTimeout + time.Second) |
| 512 | defer timer.Stop() |
| 513 | |
| 514 | select { |
| 515 | case r, ok := <-resultCh: |
| 516 | if !ok { |
| 517 | return |
| 518 | } |
| 519 | // Apply result locally; remote push is scheduled async and MUST NOT block request flow. |
| 520 | c.updateMu.Lock() |
| 521 | _, _ = c.applyRefreshResult(c.value.Load(), r) |
| 522 | c.updateMu.Unlock() |
| 523 | case <-timer.C: |
| 524 | return |
| 525 | case <-c.registry.appCtx.Done(): |
| 526 | return |
| 527 | } |
| 528 | }() |
| 529 | } |
| 530 | |
| 531 | func (c *counterInt64) tryAcquireLock(ctx context.Context) func() { |
| 532 | lock, err := c.registry.connector.Lock(ctx, c.key, c.registry.lockTtl) |
no test coverage detected