65 lines
1.1 KiB
Go
65 lines
1.1 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
const defaultIdleDispatchMaxInterval = 5 * time.Second
|
|
|
|
type idleBackoff struct {
|
|
base time.Duration
|
|
max time.Duration
|
|
next time.Duration
|
|
}
|
|
|
|
func newIdleBackoff(base, max time.Duration) idleBackoff {
|
|
if base <= 0 {
|
|
base = time.Second
|
|
}
|
|
if max < base {
|
|
max = base
|
|
}
|
|
return idleBackoff{
|
|
base: base,
|
|
max: max,
|
|
next: base,
|
|
}
|
|
}
|
|
|
|
func (b *idleBackoff) ActiveDelay() time.Duration {
|
|
b.next = b.base
|
|
return b.base
|
|
}
|
|
|
|
func (b *idleBackoff) IdleDelay() time.Duration {
|
|
delay := b.next
|
|
if b.next < b.max {
|
|
b.next *= 2
|
|
if b.next > b.max {
|
|
b.next = b.max
|
|
}
|
|
}
|
|
return delay
|
|
}
|
|
|
|
func runIdleBackoffLoop(ctx context.Context, interval, maxIdleInterval time.Duration, dispatch func(context.Context) bool) {
|
|
if dispatch == nil {
|
|
return
|
|
}
|
|
backoff := newIdleBackoff(interval, maxIdleInterval)
|
|
timer := time.NewTimer(0)
|
|
defer timer.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-timer.C:
|
|
}
|
|
if dispatch(ctx) {
|
|
timer.Reset(backoff.ActiveDelay())
|
|
continue
|
|
}
|
|
timer.Reset(backoff.IdleDelay())
|
|
}
|
|
}
|