(ctx context.Context)
| 562 | } |
| 563 | |
| 564 | func (c *Client) runWorker(ctx context.Context) { |
| 565 | consecutiveIdle := 0 |
| 566 | for { |
| 567 | select { |
| 568 | case <-ctx.Done(): |
| 569 | return |
| 570 | default: |
| 571 | } |
| 572 | didWork := c.pollOnce(ctx) |
| 573 | c.gcDoneSessions() |
| 574 | if didWork { |
| 575 | consecutiveIdle = 0 |
| 576 | continue |
| 577 | } |
| 578 | consecutiveIdle++ |
| 579 | // Capture the wake channel before entering select so we cannot |
| 580 | // miss a Broadcast() that fires between drainAll() returning |
| 581 | // empty and us entering the wait. The wake takes precedence over |
| 582 | // the timer, so backoff never delays the response to new TX. |
| 583 | wakeCh := c.wake.C() |
| 584 | select { |
| 585 | case <-ctx.Done(): |
| 586 | return |
| 587 | case <-wakeCh: |
| 588 | consecutiveIdle = 0 |
| 589 | case <-time.After(idleBackoff(consecutiveIdle)): |
| 590 | } |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | func (c *Client) runEndpointRecoveryLoop(ctx context.Context) { |
| 595 | if c.recoveryProbeAddr == "" { |
no test coverage detected