68 lines
1.2 KiB
Go
68 lines
1.2 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) {
|
||
// 有积压时立即继续 drain;interval 只用于空闲轮询。旧逻辑每个非空
|
||
// batch 也固定等待 base,形成 batch/base 的人工吞吐上限。
|
||
_ = backoff.ActiveDelay()
|
||
timer.Reset(0)
|
||
continue
|
||
}
|
||
timer.Reset(backoff.IdleDelay())
|
||
}
|
||
}
|