RateLimitManager.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /* eslint-disable
  2. no-unused-vars,
  3. */
  4. // TODO: This file was created by bulk-decaffeinate.
  5. // Fix any style issues and re-enable lint.
  6. /*
  7. * decaffeinate suggestions:
  8. * DS102: Remove unnecessary code created because of implicit returns
  9. * DS207: Consider shorter variations of null checks
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. let RateLimiter
  13. const Settings = require('@overleaf/settings')
  14. const logger = require('logger-sharelatex')
  15. const Metrics = require('./Metrics')
  16. module.exports = RateLimiter = class RateLimiter {
  17. constructor(number) {
  18. if (number == null) {
  19. number = 10
  20. }
  21. this.ActiveWorkerCount = 0
  22. this.CurrentWorkerLimit = number
  23. this.BaseWorkerCount = number
  24. }
  25. _adjustLimitUp() {
  26. this.CurrentWorkerLimit += 0.1 // allow target worker limit to increase gradually
  27. return Metrics.gauge('currentLimit', Math.ceil(this.CurrentWorkerLimit))
  28. }
  29. _adjustLimitDown() {
  30. this.CurrentWorkerLimit = Math.max(
  31. this.BaseWorkerCount,
  32. this.CurrentWorkerLimit * 0.9
  33. )
  34. logger.log(
  35. { currentLimit: Math.ceil(this.CurrentWorkerLimit) },
  36. 'reducing rate limit'
  37. )
  38. return Metrics.gauge('currentLimit', Math.ceil(this.CurrentWorkerLimit))
  39. }
  40. _trackAndRun(task, callback) {
  41. if (callback == null) {
  42. callback = function () {}
  43. }
  44. this.ActiveWorkerCount++
  45. Metrics.gauge('processingUpdates', this.ActiveWorkerCount)
  46. return task(err => {
  47. this.ActiveWorkerCount--
  48. Metrics.gauge('processingUpdates', this.ActiveWorkerCount)
  49. return callback(err)
  50. })
  51. }
  52. run(task, callback) {
  53. if (this.ActiveWorkerCount < this.CurrentWorkerLimit) {
  54. this._trackAndRun(task) // below the limit, just put the task in the background
  55. callback() // return immediately
  56. if (this.CurrentWorkerLimit > this.BaseWorkerCount) {
  57. return this._adjustLimitDown()
  58. }
  59. } else {
  60. logger.log(
  61. {
  62. active: this.ActiveWorkerCount,
  63. currentLimit: Math.ceil(this.CurrentWorkerLimit),
  64. },
  65. 'hit rate limit'
  66. )
  67. return this._trackAndRun(task, err => {
  68. if (err == null) {
  69. this._adjustLimitUp()
  70. } // don't increment rate limit if there was an error
  71. return callback(err)
  72. }) // only return after task completes
  73. }
  74. }
  75. }