49 lines
1.2 KiB
Go
49 lines
1.2 KiB
Go
package application
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"enkly/pkg/authsupport"
|
|
)
|
|
|
|
// throttle replaces Handlers.throttle: sleeps for the largest
|
|
// progressive delay among keys (honoring ctx cancellation — a gRPC
|
|
// client that gives up shouldn't leave this goroutine sleeping
|
|
// uselessly), then records an attempt against every key regardless of
|
|
// the eventual outcome. Returns false if ctx was cancelled first, in
|
|
// which case the caller should abort without doing any work (the
|
|
// monolith's handler returned straight to net/http in that case; here
|
|
// the gRPC server maps it to context.Canceled).
|
|
func throttle(ctx context.Context, l *authsupport.Limiter, keys ...string) bool {
|
|
var wait time.Duration
|
|
for _, k := range keys {
|
|
if d := l.Delay(k); d > wait {
|
|
wait = d
|
|
}
|
|
}
|
|
if !sleepCtx(ctx, wait) {
|
|
return false
|
|
}
|
|
for _, k := range keys {
|
|
l.RecordFailure(k)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// sleepCtx sleeps for d or until ctx is done, reporting whether the full
|
|
// sleep elapsed (replaces handlers.sleepCtx).
|
|
func sleepCtx(ctx context.Context, d time.Duration) bool {
|
|
if d <= 0 {
|
|
return ctx.Err() == nil
|
|
}
|
|
t := time.NewTimer(d)
|
|
defer t.Stop()
|
|
select {
|
|
case <-t.C:
|
|
return true
|
|
case <-ctx.Done():
|
|
return false
|
|
}
|
|
}
|