feat: allow throttling email sending
Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
@@ -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:^",
|
||||
|
||||
+14
-5
@@ -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 })),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user