mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
0c0facc2a1
* Avoid empty webhook processor work via cached subscription lookup
WebhookProcessor ran for every event but most teams have no matching
webhook subscription, costing an empty processor job and a database query
per event.
Cache a team's enabled subscriptions ({ id, events }) in Redis, invalidated
by model lifecycle hooks, and add an optional BaseProcessor.shouldQueue hook
consulted by the global event queue so the webhook processor only enqueues a
job when a matching subscription exists.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feedback
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import { WebhookSubscription } from "@server/models";
|
|
import BaseProcessor from "@server/queues/processors/BaseProcessor";
|
|
import type { Event } from "@server/types";
|
|
import DeliverWebhookTask from "../tasks/DeliverWebhookTask";
|
|
|
|
export default class WebhookProcessor extends BaseProcessor {
|
|
static applicableEvents: ["*"] = ["*"];
|
|
|
|
/**
|
|
* Only queue an event when the team has an enabled webhook subscription that
|
|
* matches it. The vast majority of events belong to teams with no applicable
|
|
* subscriptions, so this avoids creating and running an empty job for them.
|
|
*
|
|
* @param event The event about to be queued.
|
|
* @returns true if a matching subscription exists.
|
|
*/
|
|
static async shouldQueue(event: Event): Promise<boolean> {
|
|
if (!event.teamId) {
|
|
return false;
|
|
}
|
|
|
|
const subscriptions = await WebhookSubscription.findEnabledByTeamId(
|
|
event.teamId
|
|
);
|
|
|
|
return subscriptions.some((subscription) =>
|
|
WebhookSubscription.matchEvent(subscription.events, event.name)
|
|
);
|
|
}
|
|
|
|
async perform(event: Event) {
|
|
if (!event.teamId) {
|
|
return;
|
|
}
|
|
|
|
const subscriptions = await WebhookSubscription.findEnabledByTeamId(
|
|
event.teamId
|
|
);
|
|
|
|
const applicableSubscriptions = subscriptions.filter((subscription) =>
|
|
WebhookSubscription.matchEvent(subscription.events, event.name)
|
|
);
|
|
|
|
await Promise.all(
|
|
applicableSubscriptions.map((subscription) =>
|
|
new DeliverWebhookTask().schedule({
|
|
event,
|
|
subscriptionId: subscription.id,
|
|
})
|
|
)
|
|
);
|
|
}
|
|
}
|