QueueWorkers.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. const Features = require('./Features')
  2. const Queues = require('./Queues')
  3. const UserOnboardingEmailManager = require('../Features/User/UserOnboardingEmailManager')
  4. const UserPostRegistrationAnalyticsManager = require('../Features/User/UserPostRegistrationAnalyticsManager')
  5. const FeaturesUpdater = require('../Features/Subscription/FeaturesUpdater')
  6. const {
  7. addOptionalCleanupHandlerBeforeStoppingTraffic,
  8. addRequiredCleanupHandlerBeforeDrainingConnections,
  9. } = require('./GracefulShutdown')
  10. const EmailHandler = require('../Features/Email/EmailHandler')
  11. const logger = require('@overleaf/logger')
  12. const OError = require('@overleaf/o-error')
  13. const Modules = require('./Modules')
  14. /**
  15. * @typedef {{
  16. * data: {queueName: string,name?: string,data?: any},
  17. * }} BullJob
  18. */
  19. /**
  20. * @param {string} queueName
  21. * @param {(job: BullJob) => Promise<void>} handler
  22. */
  23. function registerQueue(queueName, handler) {
  24. if (process.env.QUEUE_PROCESSING_ENABLED === 'true') {
  25. const queue = Queues.getQueue(queueName)
  26. queue.process(handler)
  27. registerCleanup(queue)
  28. }
  29. }
  30. function start() {
  31. if (!Features.hasFeature('saas')) {
  32. return
  33. }
  34. registerQueue('scheduled-jobs', async job => {
  35. const { queueName, name, data, options } = job.data
  36. const queue = Queues.getQueue(queueName)
  37. if (name) {
  38. await queue.add(name, data || {}, options || {})
  39. } else {
  40. await queue.add(data || {}, options || {})
  41. }
  42. })
  43. registerQueue('emails-onboarding', async job => {
  44. const { userId } = job.data
  45. await UserOnboardingEmailManager.sendOnboardingEmail(userId)
  46. })
  47. registerQueue('post-registration-analytics', async job => {
  48. const { userId } = job.data
  49. await UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(userId)
  50. })
  51. registerQueue('refresh-features', async job => {
  52. const { userId, reason } = job.data
  53. await FeaturesUpdater.promises.refreshFeatures(userId, reason)
  54. })
  55. registerQueue('deferred-emails', async job => {
  56. const { emailType, opts } = job.data
  57. try {
  58. await EmailHandler.promises.sendEmail(emailType, opts)
  59. } catch (e) {
  60. const error = OError.tag(e, 'failed to send deferred email')
  61. logger.warn(error)
  62. throw error
  63. }
  64. })
  65. registerQueue('group-sso-reminder', async job => {
  66. const { userId, subscriptionId } = job.data
  67. try {
  68. await Modules.promises.hooks.fire(
  69. 'sendGroupSSOReminder',
  70. userId,
  71. subscriptionId
  72. )
  73. } catch (e) {
  74. const error = OError.tag(
  75. e,
  76. 'failed to send scheduled Group SSO account linking reminder'
  77. )
  78. logger.warn(error)
  79. throw error
  80. }
  81. })
  82. }
  83. function registerCleanup(queue) {
  84. const label = `bull queue ${queue.name}`
  85. // Stop accepting new jobs.
  86. addOptionalCleanupHandlerBeforeStoppingTraffic(label, async () => {
  87. const justThisWorker = true
  88. await queue.pause(justThisWorker)
  89. })
  90. // Wait for all jobs to process before shutting down connections.
  91. addRequiredCleanupHandlerBeforeDrainingConnections(label, async () => {
  92. await queue.close()
  93. })
  94. // Disconnect from redis is scheduled in queue setup.
  95. }
  96. module.exports = { start, registerQueue }