snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
35
internal/tools/interval_limiter.go
Normal file
35
internal/tools/interval_limiter.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IntervalLimiter permits an action at most once per configured interval. It is
|
||||
// safe for concurrent use and does no allocation or locking on the hot path -
|
||||
// just an atomic load (and a single CAS when the action is actually allowed),
|
||||
// so guarding a rare log line with it is effectively free when the interval has
|
||||
// not elapsed.
|
||||
type IntervalLimiter struct {
|
||||
intervalNanos int64
|
||||
lastNanos atomic.Int64
|
||||
}
|
||||
|
||||
// NewIntervalLimiter creates an IntervalLimiter that allows an action at most
|
||||
// once per interval.
|
||||
func NewIntervalLimiter(interval time.Duration) *IntervalLimiter {
|
||||
return &IntervalLimiter{intervalNanos: int64(interval)}
|
||||
}
|
||||
|
||||
// Allow reports whether the action may run now. Across all concurrent callers it
|
||||
// returns true at most once per interval. The first call always returns true.
|
||||
func (l *IntervalLimiter) Allow() bool {
|
||||
now := time.Now().UnixNano()
|
||||
last := l.lastNanos.Load()
|
||||
if now-last < l.intervalNanos {
|
||||
return false
|
||||
}
|
||||
// Only the caller that swaps in the new timestamp is allowed to proceed, so
|
||||
// concurrent callers in the same window can't all log.
|
||||
return l.lastNanos.CompareAndSwap(last, now)
|
||||
}
|
||||
Reference in New Issue
Block a user