rate-limit.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package common
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. type InMemoryRateLimiter struct {
  7. store map[string]*[]int64
  8. mutex sync.Mutex
  9. expirationDuration time.Duration
  10. }
  11. func (l *InMemoryRateLimiter) Init(expirationDuration time.Duration) {
  12. if l.store == nil {
  13. l.mutex.Lock()
  14. if l.store == nil {
  15. l.store = make(map[string]*[]int64)
  16. l.expirationDuration = expirationDuration
  17. if expirationDuration > 0 {
  18. go l.clearExpiredItems()
  19. }
  20. }
  21. l.mutex.Unlock()
  22. }
  23. }
  24. func (l *InMemoryRateLimiter) clearExpiredItems() {
  25. for {
  26. time.Sleep(l.expirationDuration)
  27. l.mutex.Lock()
  28. now := time.Now().Unix()
  29. for key := range l.store {
  30. queue := l.store[key]
  31. size := len(*queue)
  32. if size == 0 || now-(*queue)[size-1] > int64(l.expirationDuration.Seconds()) {
  33. delete(l.store, key)
  34. }
  35. }
  36. l.mutex.Unlock()
  37. }
  38. }
  39. // Request parameter duration's unit is seconds
  40. func (l *InMemoryRateLimiter) Request(key string, maxRequestNum int, duration int64) bool {
  41. l.mutex.Lock()
  42. defer l.mutex.Unlock()
  43. // [old <-- new]
  44. queue, ok := l.store[key]
  45. now := time.Now().Unix()
  46. if ok {
  47. if len(*queue) < maxRequestNum {
  48. *queue = append(*queue, now)
  49. return true
  50. } else {
  51. if now-(*queue)[0] >= duration {
  52. *queue = (*queue)[1:]
  53. *queue = append(*queue, now)
  54. return true
  55. } else {
  56. return false
  57. }
  58. }
  59. } else {
  60. s := make([]int64, 0, maxRequestNum)
  61. l.store[key] = &s
  62. *(l.store[key]) = append(*(l.store[key]), now)
  63. }
  64. return true
  65. }