0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Improved email concurrency sending (#15923)

no issue

Send 10 batches at the same time
This commit is contained in:
Simon Backx 2022-12-02 15:30:02 +01:00 committed by GitHub
parent f562d19f3c
commit ea72934c41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 9 deletions

View file

@ -12,6 +12,18 @@ const {MailgunEmailProvider} = require('@tryghost/email-service');
const mobileDocWithPaywall = '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["paywall",{}]],"sections":[[1,"p",[[0,[],0,"Free content"]]],[10,0],[1,"p",[[0,[],0,"Members content"]]]]}';
function sortBatches(a, b) {
const aId = a.get('provider_id');
const bId = b.get('provider_id');
if (aId === null) {
return 1;
}
if (bId === null) {
return -1;
}
return aId.localeCompare(bId);
}
async function createPublishedPostEmail(settings = {}, email_recipient_filter) {
const post = {
title: 'A random test post',
@ -309,9 +321,12 @@ describe('Batch sending tests', function () {
assert.equal(emailModel.get('email_count'), 4);
// Did we create batches?
let batches = await models.EmailBatch.findAll({filter: `email_id:${emailModel.id}`, order: 'provider_id ASC'});
let batches = await models.EmailBatch.findAll({filter: `email_id:${emailModel.id}`});
assert.equal(batches.models.length, 4);
// sort batches by provider_id (nullable) because findAll doesn't have order option
batches.models.sort(sortBatches);
let emailRecipients = [];
// Check all batches are in send state
@ -334,7 +349,7 @@ describe('Batch sending tests', function () {
assert.equal(batch.get('error_message'), null);
assert.equal(batch.get('error_data'), null);
}
assert.equal(batch.get('member_segment'), null);
// Did we create recipients?
@ -353,12 +368,19 @@ describe('Batch sending tests', function () {
await completedPromise;
await emailModel.refresh();
batches = await models.EmailBatch.findAll({filter: `email_id:${emailModel.id}`, order: 'provider_id ASC'});
batches = await models.EmailBatch.findAll({filter: `email_id:${emailModel.id}`});
// sort batches by provider_id (nullable) because findAll doesn't have order option
batches.models.sort(sortBatches);
assert.equal(emailModel.get('status'), 'submitted');
assert.equal(emailModel.get('email_count'), 4);
// Did we keep the batches?
batches = await models.EmailBatch.findAll({filter: `email_id:${emailModel.id}`, order: 'provider_id ASC'});
batches = await models.EmailBatch.findAll({filter: `email_id:${emailModel.id}`});
// sort batches by provider_id (nullable) because findAll doesn't have order option
batches.models.sort(sortBatches);
assert.equal(batches.models.length, 4);
emailRecipients = [];

View file

@ -249,13 +249,23 @@ class BatchSendingService {
logging.info(`Sending ${batches.length} batches for email ${email.id}`);
// Loop batches and send them via the EmailProvider
// TODO: introduce concurrency when sending (need a replacement for bluebird)
let succeededCount = 0;
for (const batch of batches) {
if (await this.sendBatch({email, batch, post, newsletter})) {
succeededCount += 1;
const queue = batches.slice();
// Bind this
let runNext;
runNext = async () => {
const batch = queue.shift();
if (batch) {
if (await this.sendBatch({email, batch, post, newsletter})) {
succeededCount += 1;
}
await runNext();
}
}
};
// Run maximum 10 at the same time
await Promise.all(new Array(10).fill(0).map(() => runNext()));
if (succeededCount < batches.length) {
if (succeededCount > 0) {