RateLimiter.js 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. const settings = require('@overleaf/settings')
  2. const Metrics = require('@overleaf/metrics')
  3. const RedisWrapper = require('./RedisWrapper')
  4. const rclient = RedisWrapper.client('ratelimiter')
  5. const { RedisRateLimiter } = require('rolling-rate-limiter')
  6. const { callbackify } = require('util')
  7. async function addCount(opts) {
  8. if (settings.disableRateLimits) {
  9. return true
  10. }
  11. const namespace = `RateLimit:${opts.endpointName}:`
  12. const k = `{${opts.subjectName}}`
  13. const limiter = new RedisRateLimiter({
  14. client: rclient,
  15. namespace,
  16. interval: opts.timeInterval * 1000,
  17. maxInInterval: opts.throttle,
  18. })
  19. const rateLimited = await limiter.limit(k)
  20. if (rateLimited) {
  21. Metrics.inc('rate-limit-hit', 1, {
  22. path: opts.endpointName,
  23. })
  24. }
  25. return !rateLimited
  26. }
  27. async function clearRateLimit(endpointName, subject) {
  28. // same as the key which will be built by RollingRateLimiter (namespace+k)
  29. const keyName = `RateLimit:${endpointName}:{${subject}}`
  30. await rclient.del(keyName)
  31. }
  32. module.exports = {
  33. addCount: callbackify(addCount),
  34. clearRateLimit: callbackify(clearRateLimit),
  35. promises: {
  36. addCount,
  37. clearRateLimit,
  38. },
  39. }