package throttling import ( "time" ) // Throttling notifications to prometheus and web clients // TO be used in a single-threaded manner. // // NOTE: the null value of type T is considered as a not-set value. // // The best usage of Throttler is with a pointer type. type Throttler[T comparable] struct { minDelay time.Duration // ucntion to call to implement the notification. notifier func(t T) lastReportedTime time.Time pendingValue T lastValue T } func NewThrottler[T comparable](notifier func(t T), minDelay time.Duration) Throttler[T] { throttler := Throttler[T]{ minDelay: minDelay, notifier: notifier, lastReportedTime: time.Time{}, pendingValue: *new(T), lastValue: *new(T), } return throttler } // Notify there is a new value. Performs notification if it was long enough ago // for the last notification to be sent. If not, it is stored as a pending event to // be sent later. New events that come in before a notification is sent override the // pending event. func (throttler *Throttler[T]) Notify(value T) { if throttler.lastValue == value { // duplicate events are not sent. return } if clock.time().Sub(throttler.lastReportedTime) >= throttler.minDelay { throttler.notifier(value) throttler.lastReportedTime = clock.time() throttler.lastValue = value throttler.pendingValue = *new(T) return } throttler.pendingValue = value } // To be called periodically. It sends out any pending events if the time the last // notification was sent is long enough ago. func (throttler *Throttler[T]) Ping() { if throttler.pendingValue != *new(T) { throttler.Notify(throttler.pendingValue) } }