1
0

limiter.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package ratelimit
  2. import (
  3. "fmt"
  4. "math"
  5. "sync/atomic"
  6. "time"
  7. )
  8. // Limiter is a token bucket: `burst` calls are allowed at once, then one more per `every`.
  9. // It counts the calls it denies and hands that count to the next allowed call.
  10. //
  11. // The budget belongs to the Limiter instance.
  12. // Every Allow that returns true spends from it, whatever the caller then does.
  13. //
  14. // Time follows Go's monotonic clock.
  15. //
  16. // Create one Limiter for each thing you want to limit,
  17. // sharing one between unrelated events lets the noisy one starve the quiet one.
  18. //
  19. // Check Allow before doing the work being limited, so a denied call stays cheap:
  20. //
  21. // if denied, ok := probeLimiter.Allow(); ok {
  22. // sendProbe()
  23. // probesDenied.Inc(int64(denied))
  24. // }
  25. //
  26. // For log lines use logging.RateLimited, which attaches the denied count to the logger as "suppressed".
  27. type Limiter struct {
  28. every int64
  29. slack int64
  30. tat atomic.Int64
  31. denied atomic.Uint64
  32. }
  33. // maxSpan bounds `burst` * `every` to half of int64, leaving the other half for process uptime so the bucket
  34. // math can't overflow.
  35. const maxSpan = math.MaxInt64 / 2
  36. // New returns a Limiter allowing `burst` calls at once and one more per `every`.
  37. // A `burst` under 1 is 1, and an `every` of 0 or less never limits.
  38. // It returns an error if `burst` * `every` is over about 146 years.
  39. func New(burst int, every time.Duration) (*Limiter, error) {
  40. l := &Limiter{}
  41. if every > 0 {
  42. burst = max(burst, 1)
  43. if int64(burst) > maxSpan/int64(every) {
  44. return nil, fmt.Errorf("ratelimit: burst %d * every %v is too long", burst, every)
  45. }
  46. l.every = int64(every)
  47. l.slack = int64(burst-1) * l.every
  48. }
  49. return l, nil
  50. }
  51. var monoStart = time.Now()
  52. func monoNow() int64 { return int64(time.Since(monoStart)) }
  53. // Allow reports whether this call is allowed.
  54. // If a token is available it spends it and returns the calls denied since the last allowed one, and true.
  55. // Otherwise it returns 0 and false, and counts the denial.
  56. // A nil Limiter allows everything.
  57. func (l *Limiter) Allow() (uint64, bool) {
  58. if l == nil {
  59. return 0, true
  60. }
  61. return l.allow(monoNow())
  62. }
  63. // allow is Allow at a given monotonic time.
  64. func (l *Limiter) allow(now int64) (uint64, bool) {
  65. // Concurrent Allow calls read the clock before racing for the bucket, so one can see a time another already spent
  66. // past and be denied. An unlimited Limiter must never deny, so it skips the bucket.
  67. if l.every == 0 {
  68. return 0, true
  69. }
  70. for {
  71. tat := l.tat.Load()
  72. next := max(tat, now)
  73. if next-now > l.slack {
  74. l.denied.Add(1)
  75. return 0, false
  76. }
  77. if l.tat.CompareAndSwap(tat, next+l.every) {
  78. return l.denied.Swap(0), true
  79. }
  80. }
  81. }