feat: add rate limit configuration

Signed-off-by: Kai Dubauskas <kai.dubauskas@doordash.com>
This commit is contained in:
Kai Dubauskas
2025-11-17 16:36:58 -05:00
parent 7933a529bf
commit b80857ab0b
3 changed files with 79 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-notifications-backend-module-slack': patch
---
The rate limit is now a config variable
@@ -953,4 +953,65 @@ describe('SlackNotificationProcessor', () => {
);
});
});
describe('when rate limit is not configured', () => {
it('should use default rate limit of 10 messages per minute', async () => {
const slack = new WebClient();
const processor = SlackNotificationProcessor.fromConfig(config, {
auth,
logger,
catalog: catalogServiceMock({
entities: DEFAULT_ENTITIES_RESPONSE.items,
}),
slack,
})[0];
await processor.processOptions({
recipients: { type: 'entity', entityRef: 'group:default/mock' },
payload: { title: 'notification' },
});
expect(slack.chat.postMessage).toHaveBeenCalled();
});
});
describe('when rate limit is configured', () => {
it('should use custom rate limit value', async () => {
const slack = new WebClient();
const rateLimitConfig = mockServices.rootConfig({
data: {
app: {
baseUrl: 'https://example.org',
},
notifications: {
processors: {
slack: [
{
token: 'mock-token',
rateLimit: 5,
},
],
},
},
},
});
const processor = SlackNotificationProcessor.fromConfig(rateLimitConfig, {
auth,
logger,
catalog: catalogServiceMock({
entities: DEFAULT_ENTITIES_RESPONSE.items,
}),
slack,
})[0];
await processor.processOptions({
recipients: { type: 'entity', entityRef: 'group:default/mock' },
payload: { title: 'notification' },
});
expect(slack.chat.postMessage).toHaveBeenCalled();
});
});
});
@@ -68,10 +68,12 @@ export class SlackNotificationProcessor implements NotificationProcessor {
const slack = options.slack ?? new WebClient(token);
const broadcastChannels = c.getOptionalStringArray('broadcastChannels');
const username = c.getOptionalString('username');
const rateLimit = c.getOptionalNumber('rateLimit');
return new SlackNotificationProcessor({
slack,
broadcastChannels,
username,
rateLimit,
...options,
});
});
@@ -84,9 +86,17 @@ export class SlackNotificationProcessor implements NotificationProcessor {
catalog: CatalogService;
broadcastChannels?: string[];
username?: string;
rateLimit?: number;
}) {
const { auth, catalog, logger, slack, broadcastChannels, username } =
options;
const {
auth,
catalog,
logger,
slack,
broadcastChannels,
username,
rateLimit,
} = options;
this.logger = logger;
this.catalog = catalog;
this.auth = auth;
@@ -134,7 +144,7 @@ export class SlackNotificationProcessor implements NotificationProcessor {
);
const throttle = pThrottle({
limit: 10,
limit: rateLimit ?? 10,
interval: durationToMilliseconds({ minutes: 1 }),
});
const throttled = throttle((opts: ChatPostMessageArguments) =>