feat: allow throttling email sending

Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
Heikki Hellgren
2024-04-24 10:30:28 +03:00
parent 4e4e5607e2
commit 49295af2c1
4 changed files with 27 additions and 7 deletions
@@ -91,6 +91,10 @@ export interface Config {
* Concurrency limit for email sending, defaults to 2
*/
concurrencyLimit?: number;
/**
* Throttle duration between email sending, defaults to 100ms
*/
throttleInterval?: HumanDuration;
/**
* Configuration for broadcast notifications
*/
@@ -45,7 +45,7 @@
"@backstage/types": "workspace:^",
"lodash": "^4.17.21",
"nodemailer": "^6.9.13",
"p-limit": "^3.1.0"
"p-throttle": "^6.1.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
@@ -39,7 +39,7 @@ import { compact } from 'lodash';
import { DefaultAwsCredentialsManager } from '@backstage/integration-aws-node';
import { NotificationTemplateRenderer } from '../extensions';
import Mail from 'nodemailer/lib/mailer';
import pLimit from 'p-limit';
import pThrottle from 'p-throttle';
export class NotificationsEmailProcessor implements NotificationProcessor {
private transporter: any;
@@ -49,6 +49,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor {
private readonly replyTo?: string;
private readonly cacheTtl: number;
private readonly concurrencyLimit: number;
private readonly throttleInterval: number;
constructor(
private readonly logger: LoggerService,
@@ -68,6 +69,11 @@ export class NotificationsEmailProcessor implements NotificationProcessor {
this.replyTo = emailProcessorConfig.getOptionalString('replyTo');
this.concurrencyLimit =
emailProcessorConfig.getOptionalNumber('concurrencyLimit') ?? 2;
const throttleConfig =
emailProcessorConfig.getOptionalConfig('throttleInterval');
this.throttleInterval = throttleConfig
? durationToMilliseconds(readDurationFromConfig(throttleConfig))
: 100;
const cacheConfig = emailProcessorConfig.getOptionalConfig('cache.ttl');
this.cacheTtl = cacheConfig
? durationToMilliseconds(readDurationFromConfig(cacheConfig))
@@ -198,11 +204,14 @@ export class NotificationsEmailProcessor implements NotificationProcessor {
}
private async sendMails(options: Mail.Options, emails: string[]) {
const limit = pLimit(this.concurrencyLimit);
const throttle = pThrottle({
limit: this.concurrencyLimit,
interval: this.throttleInterval,
});
const throttled = throttle((opts: Mail.Options) => this.sendMail(opts));
await Promise.all(
emails.map(email =>
limit(() => this.sendMail({ ...options, to: email })),
),
emails.map(email => throttled({ ...options, to: email })),
);
}
+8 -1
View File
@@ -6051,7 +6051,7 @@ __metadata:
"@types/nodemailer": ^6.4.14
lodash: ^4.17.21
nodemailer: ^6.9.13
p-limit: ^3.1.0
p-throttle: ^6.1.0
languageName: unknown
linkType: soft
@@ -33255,6 +33255,13 @@ __metadata:
languageName: node
linkType: hard
"p-throttle@npm:^6.1.0":
version: 6.1.0
resolution: "p-throttle@npm:6.1.0"
checksum: c1947cca8844564c3d86f8c09067add5e7398b87898cb1f1aea5c48d2c211590d039a316d28a4b0d95364ffa0213c01dff6bf71175c468eab0e381f77715dbdb
languageName: node
linkType: hard
"p-timeout@npm:^3.2.0":
version: 3.2.0
resolution: "p-timeout@npm:3.2.0"