feature/IO-3096-GlobalNotifications - Cleanup and Package bumps
This commit is contained in:
@@ -4,30 +4,44 @@ const { sendTaskEmail } = require("../../email/sendemail");
|
||||
let emailQueue;
|
||||
let worker;
|
||||
|
||||
const loadEmailQueue = async ({ pubClient, logger, redisHelpers }) => {
|
||||
// Consolidate the same way the App Queue Does.
|
||||
|
||||
/**
|
||||
* Initializes the email queue and worker for sending notifications via email.
|
||||
*
|
||||
* @param {Object} options - Configuration options for queue initialization.
|
||||
* @param {Object} options.pubClient - Redis client instance for queue communication.
|
||||
* @param {Object} options.logger - Logger instance for logging events and debugging.
|
||||
* @returns {Queue} The initialized `emailQueue` instance for dispatching emails.
|
||||
*/
|
||||
const loadEmailQueue = async ({ pubClient, logger }) => {
|
||||
// Only initialize if queue doesn't already exist
|
||||
if (!emailQueue) {
|
||||
logger.logger.info("Initializing Notifications Email Queue");
|
||||
|
||||
// Create queue for email notifications
|
||||
emailQueue = new Queue("notificationsEmails", {
|
||||
connection: pubClient,
|
||||
prefix: "{BULLMQ}",
|
||||
prefix: "{BULLMQ}", // Namespace prefix for BullMQ in Redis
|
||||
defaultJobOptions: {
|
||||
attempts: 3,
|
||||
attempts: 3, // Retry failed jobs up to 3 times
|
||||
backoff: {
|
||||
type: "exponential",
|
||||
delay: 1000
|
||||
type: "exponential", // Exponential backoff strategy
|
||||
delay: 1000 // Initial delay of 1 second
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the worker during queue setup
|
||||
// Worker to process jobs from the emailQueue
|
||||
worker = new Worker(
|
||||
"notificationsEmails",
|
||||
async (job) => {
|
||||
const { subject, body, recipients } = job.data;
|
||||
logger.logger.debug(`Processing email job ${job.id} for ${recipients.length} recipients`);
|
||||
const { subject, body, recipient } = job.data;
|
||||
logger.logger.debug(`Processing email job ${job.id} for recipient ${recipient}`);
|
||||
|
||||
// Send email to a single recipient
|
||||
await sendTaskEmail({
|
||||
to: recipients.map((r) => r.user),
|
||||
to: recipient, // Single email address
|
||||
subject,
|
||||
type: "text",
|
||||
text: body
|
||||
@@ -38,9 +52,9 @@ const loadEmailQueue = async ({ pubClient, logger, redisHelpers }) => {
|
||||
{
|
||||
connection: pubClient,
|
||||
prefix: "{BULLMQ}",
|
||||
concurrency: 2, // Reduced for multi-node setup; adjust based on load
|
||||
concurrency: 2, // Process up to 2 jobs concurrently
|
||||
limiter: {
|
||||
max: 10, // Max 10 jobs per minute per worker
|
||||
max: 10, // Maximum of 10 jobs per minute
|
||||
duration: 60 * 1000 // 1 minute
|
||||
}
|
||||
}
|
||||
@@ -59,7 +73,7 @@ const loadEmailQueue = async ({ pubClient, logger, redisHelpers }) => {
|
||||
logger.logger.error("Worker error:", { error: err });
|
||||
});
|
||||
|
||||
// Graceful shutdown handling
|
||||
// Graceful shutdown handler for the worker
|
||||
const shutdown = async () => {
|
||||
if (worker) {
|
||||
logger.logger.info("Closing email queue worker...");
|
||||
@@ -68,13 +82,19 @@ const loadEmailQueue = async ({ pubClient, logger, redisHelpers }) => {
|
||||
}
|
||||
};
|
||||
|
||||
process.on("SIGTERM", shutdown);
|
||||
process.on("SIGINT", shutdown);
|
||||
process.on("SIGTERM", shutdown); // Handle termination signal
|
||||
process.on("SIGINT", shutdown); // Handle interrupt signal (e.g., Ctrl+C)
|
||||
}
|
||||
|
||||
return emailQueue;
|
||||
return emailQueue; // Return queue for external use
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the initialized `emailQueue` instance.
|
||||
*
|
||||
* @returns {Queue} The `emailQueue` instance for sending emails.
|
||||
* @throws {Error} If `emailQueue` is not initialized (i.e., `loadEmailQueue` wasn’t called).
|
||||
*/
|
||||
const getQueue = () => {
|
||||
if (!emailQueue) {
|
||||
throw new Error("Email queue not initialized. Ensure loadEmailQueue is called during bootstrap.");
|
||||
@@ -82,17 +102,31 @@ const getQueue = () => {
|
||||
return emailQueue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches emails to the `emailQueue` for processing, creating one job per recipient.
|
||||
*
|
||||
* @param {Object} options - Options for dispatching emails.
|
||||
* @param {Array} options.emailsToDispatch - Array of email objects to dispatch.
|
||||
* @param {Object} options.logger - Logger instance for logging dispatch events.
|
||||
* @returns {Promise<void>} Resolves when all email jobs are added to the queue.
|
||||
*/
|
||||
const dispatchEmailsToQueue = async ({ emailsToDispatch, logger }) => {
|
||||
const emailQueue = getQueue();
|
||||
|
||||
for (const email of emailsToDispatch) {
|
||||
const { subject, body, recipients } = email;
|
||||
await emailQueue.add("send-email", {
|
||||
subject,
|
||||
body,
|
||||
recipients
|
||||
}); // Job options moved to defaultJobOptions in Queue
|
||||
logger.logger.debug(`Added email to queue: ${subject} for ${recipients.length} recipients`);
|
||||
// Create an array of jobs, one per recipient
|
||||
const jobs = recipients.map((recipient) => ({
|
||||
name: "send-email",
|
||||
data: {
|
||||
subject,
|
||||
body,
|
||||
recipient: recipient.user // Extract the email address from recipient object
|
||||
}
|
||||
}));
|
||||
// Add all jobs for this email in one operation
|
||||
await emailQueue.addBulk(jobs);
|
||||
logger.logger.debug(`Added ${jobs.length} email jobs to queue for subject: ${subject}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user