feature/IO-3096-GlobalNotifications - Checkpoint, App Queue

This commit is contained in:
Dave Richer
2025-02-18 14:29:07 -05:00
parent c1ea8e8a3d
commit 00005c881e

View File

@@ -18,6 +18,8 @@ const loadAppQueue = async ({ pubClient, logger, redisHelpers, ioRedis }) => {
const redisKey = `app:notifications:${jobId}`;
const lastSentKey = `${redisKey}:lastSent`;
const lockKey = `lock:send-notifications:${jobId}`;
const recurringFlagKey = `app:recurring:${jobId}`;
if (job.name === "add-notification") {
const notification = { key, variables, timestamp: Date.now() };
@@ -63,22 +65,31 @@ const loadAppQueue = async ({ pubClient, logger, redisHelpers, ioRedis }) => {
if (hasNewNotifications) {
await pubClient.set(lastSentKey, Date.now(), "EX", 300);
} else {
// Only remove if no active "add-notification" jobs are pending
const activeJobs = await appQueue.getActive();
const hasPendingAdds = activeJobs.some((j) => j.name === "add-notification" && j.data.jobId === jobId);
if (!hasPendingAdds) {
const recurringJobKey = `send-notifications:${jobId}`;
const removed = await appQueue.removeRepeatable("send-notifications", {
every: 30 * 1000,
jobId: recurringJobKey
});
if (removed) {
logger.logger.info(
`Successfully removed recurring send-notifications job for jobId ${jobId} due to no new notifications`
);
const lockAcquired = await pubClient.set(lockKey, "locked", "NX", "EX", 10);
if (lockAcquired) {
const recurringJobKey = `send-notifications:${jobId}`;
const repeatableJobs = await appQueue.getRepeatableJobs();
const jobExists = repeatableJobs.some((j) => j.key === recurringJobKey);
if (jobExists) {
await appQueue.removeRepeatableByKey(recurringJobKey);
// Drain all remaining send-notifications jobs for this jobId
await appQueue.drain(false); // false to not force removal of active jobs
logger.logger.info(
`Successfully removed recurring send-notifications job and drained queue for jobId ${jobId} with key ${recurringJobKey}`
);
} else {
logger.logger.info(
`No recurring send-notifications job found for jobId ${jobId} with key ${recurringJobKey} - processing leftover scheduled instance`
);
}
await pubClient.del(lockKey);
await pubClient.del(recurringFlagKey);
} else {
logger.logger.warn(
`Failed to remove recurring send-notifications job for jobId ${jobId} - may already be removed`
logger.logger.info(
`Skipped removal of send-notifications for jobId ${jobId} - lock held by another worker`
);
}
} else {
@@ -100,20 +111,25 @@ const loadAppQueue = async ({ pubClient, logger, redisHelpers, ioRedis }) => {
if (job.name === "add-notification") {
const { jobId } = job.data;
const recurringJobKey = `send-notifications:${jobId}`;
const existingJobs = await appQueue.getRepeatableJobs();
if (!existingJobs.some((j) => j.key === recurringJobKey)) {
await appQueue.add(
"send-notifications",
{ jobId, bodyShopId: job.data.bodyShopId, recipients: job.data.recipients },
{
repeat: {
every: 30 * 1000, // Every 30 seconds
limit: 10 // 5 minutes
},
jobId: recurringJobKey
}
);
logger.logger.info(`Scheduled 30s notification send for jobId ${jobId}`);
const recurringFlagKey = `app:recurring:${jobId}`;
const flagSet = await pubClient.setnx(recurringFlagKey, "active");
if (flagSet) {
const existingJobs = await appQueue.getRepeatableJobs();
if (!existingJobs.some((j) => j.key === recurringJobKey)) {
await appQueue.add(
"send-notifications",
{ jobId, bodyShopId: job.data.bodyShopId, recipients: job.data.recipients },
{
repeat: {
every: 30 * 1000,
limit: 10
},
jobId: recurringJobKey
}
);
logger.logger.info(`Scheduled 30s notification send for jobId ${jobId} with key ${recurringJobKey}`);
await pubClient.expire(recurringFlagKey, 300);
}
}
}
logger.logger.info(`Job ${job.id} completed`);