Optional
options: Omit<undefined | EnqueueOptions, "unique" | "idempotencyKey">The following are true:
Taken together, we need to ensure each job only contains one chunk of recipients so it either
succeeds or fails and retries on its own. If we moved chunking to the
NotificationClient.trigger
method, for example, the following could happen:
Now the job will fail indefinitely and the later batches won't get their notifications.
Even if you're sure you won't have more >MAXIMUM_RECIPIENTS_COUNT recipients, the method
enforces other best practices, like setting expiresAt
on enqueue instead of calculating it in
your job on each run. Doing this usually means it's always in the future and doesn't help
prevent stale notifications.
So please, use this method if not for customers, then to save fellow engineers time debugging!
import {
type ExampleNotificationEnqueueData,
ExampleNotificationJob,
} from "./exampleNotification.job";
import { notificationJobEnqueuer } from "./notificationJobEnqueuer";
async function enqueueNotificationJob() {
await notificationJobEnqueuer.enqueueOneOrMore<ExampleNotificationEnqueueData>(
ExampleNotificationJob,
{
// Set expiresAt at enqueue-time so it remains stable across job retries.
expiresAt: minutesFromNow(60).toISOString(),
// Set idempotencyKey at enqueue-time so it remains stable across job retries.
idempotencyKey: {
resourceId: "event-123",
},
// Set recipients at enqueue-time so they respect our notification provider's limits.
recipients: ["user-1"],
workflowKey: "event-starting-reminder",
// Any additional enqueue-time data passed to the job:
workplaceId: "workplace-123",
},
);
}
// eslint-disable-next-line unicorn/prefer-top-level-await
void enqueueNotificationJob();
function minutesFromNow(minutes: number) {
return new Date(Date.now() + minutes * 60_000);
}
In short: It's important that notification jobs use this method. It enforces best practices to ensure customers don't receive duplicate or stale notifications.