mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #9319 from overleaf/mj-deferred-recurly-email
[web] Use bull queues for deferred cancellation email GitOrigin-RevId: a104f9940badcffc15f1f237a1cefd5dd912f4e0
This commit is contained in:
parent
4cfbee15df
commit
f5b2cdc3cb
5 changed files with 69 additions and 15 deletions
|
@ -2,11 +2,13 @@ const { callbackify } = require('util')
|
|||
const Settings = require('@overleaf/settings')
|
||||
const EmailBuilder = require('./EmailBuilder')
|
||||
const EmailSender = require('./EmailSender')
|
||||
const Queues = require('../../infrastructure/Queues')
|
||||
|
||||
const EMAIL_SETTINGS = Settings.email || {}
|
||||
|
||||
module.exports = {
|
||||
sendEmail: callbackify(sendEmail),
|
||||
sendDeferredEmail,
|
||||
promises: {
|
||||
sendEmail,
|
||||
},
|
||||
|
@ -22,3 +24,11 @@ async function sendEmail(emailType, opts) {
|
|||
opts.subject = email.subject
|
||||
await EmailSender.promises.sendEmail(opts)
|
||||
}
|
||||
|
||||
function sendDeferredEmail(emailType, opts, delay) {
|
||||
Queues.createScheduledJob(
|
||||
'deferred-emails',
|
||||
{ data: { emailType, opts } },
|
||||
delay
|
||||
)
|
||||
}
|
||||
|
|
|
@ -199,20 +199,9 @@ function cancelSubscription(user, callback) {
|
|||
first_name: user.first_name,
|
||||
}
|
||||
const ONE_HOUR_IN_MS = 1000 * 60 * 60
|
||||
setTimeout(
|
||||
() =>
|
||||
EmailHandler.sendEmail(
|
||||
'canceledSubscription',
|
||||
emailOpts,
|
||||
err => {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err },
|
||||
'failed to send confirmation email for subscription cancellation'
|
||||
)
|
||||
}
|
||||
}
|
||||
),
|
||||
EmailHandler.sendDeferredEmail(
|
||||
'canceledSubscription',
|
||||
emailOpts,
|
||||
ONE_HOUR_IN_MS
|
||||
)
|
||||
callback()
|
||||
|
|
|
@ -7,6 +7,9 @@ const {
|
|||
addOptionalCleanupHandlerBeforeStoppingTraffic,
|
||||
addRequiredCleanupHandlerBeforeDrainingConnections,
|
||||
} = require('./GracefulShutdown')
|
||||
const EmailHandler = require('../Features/Email/EmailHandler')
|
||||
const logger = require('@overleaf/logger')
|
||||
const OError = require('@overleaf/o-error')
|
||||
|
||||
function start() {
|
||||
if (!Features.hasFeature('saas')) {
|
||||
|
@ -47,6 +50,19 @@ function start() {
|
|||
await FeaturesUpdater.promises.refreshFeatures(userId, reason)
|
||||
})
|
||||
registerCleanup(refreshFeaturesQueue)
|
||||
|
||||
const deferredEmailsQueue = Queues.getQueue('deferred-emails')
|
||||
deferredEmailsQueue.process(async job => {
|
||||
const { emailType, opts } = job.data
|
||||
try {
|
||||
await EmailHandler.promises.sendEmail(emailType, opts)
|
||||
} catch (e) {
|
||||
const error = OError.tag(e, 'failed to send deferred email')
|
||||
logger.warn(error)
|
||||
throw error
|
||||
}
|
||||
})
|
||||
registerCleanup(deferredEmailsQueue)
|
||||
}
|
||||
|
||||
function registerCleanup(queue) {
|
||||
|
|
|
@ -20,11 +20,15 @@ describe('EmailHandler', function () {
|
|||
sendEmail: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
this.Queues = {
|
||||
createScheduledJob: sinon.stub(),
|
||||
}
|
||||
this.EmailHandler = SandboxedModule.require(MODULE_PATH, {
|
||||
requires: {
|
||||
'./EmailBuilder': this.EmailBuilder,
|
||||
'./EmailSender': this.EmailSender,
|
||||
'@overleaf/settings': this.Settings,
|
||||
'../../infrastructure/Queues': this.Queues,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
@ -92,4 +96,27 @@ describe('EmailHandler', function () {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('send deferred email', function () {
|
||||
beforeEach(function () {
|
||||
this.opts = {
|
||||
to: 'bob@bob.com',
|
||||
first_name: 'hello bob',
|
||||
}
|
||||
this.emailType = 'canceledSubscription'
|
||||
this.ONE_HOUR_IN_MS = 1000 * 60 * 60
|
||||
this.EmailHandler.sendDeferredEmail(
|
||||
this.emailType,
|
||||
this.opts,
|
||||
this.ONE_HOUR_IN_MS
|
||||
)
|
||||
})
|
||||
it('should add a email job to the queue', function () {
|
||||
expect(this.Queues.createScheduledJob).to.have.been.calledWith(
|
||||
'deferred-emails',
|
||||
{ data: { emailType: this.emailType, opts: this.opts } },
|
||||
this.ONE_HOUR_IN_MS
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -110,7 +110,10 @@ describe('SubscriptionHandler', function () {
|
|||
|
||||
this.LimitationsManager = { userHasV2Subscription: sinon.stub() }
|
||||
|
||||
this.EmailHandler = { sendEmail: sinon.stub() }
|
||||
this.EmailHandler = {
|
||||
sendEmail: sinon.stub(),
|
||||
sendDeferredEmail: sinon.stub(),
|
||||
}
|
||||
|
||||
this.AnalyticsManager = { recordEventForUser: sinon.stub() }
|
||||
|
||||
|
@ -405,6 +408,15 @@ describe('SubscriptionHandler', function () {
|
|||
.calledWith(this.subscription.recurlySubscription_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should send the email after 1 hour', function () {
|
||||
const ONE_HOUR_IN_MS = 1000 * 60 * 60
|
||||
expect(this.EmailHandler.sendDeferredEmail).to.have.been.calledWith(
|
||||
'canceledSubscription',
|
||||
{ to: this.user.email, first_name: this.user.first_name },
|
||||
ONE_HOUR_IN_MS
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue