Files
bodyshop/server/notifications/queues/emailQueue.js

134 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { Queue, Worker } = require("bullmq");
const { sendTaskEmail } = require("../../email/sendemail");
let emailQueue;
let worker;
// 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}", // Namespace prefix for BullMQ in Redis
defaultJobOptions: {
attempts: 3, // Retry failed jobs up to 3 times
backoff: {
type: "exponential", // Exponential backoff strategy
delay: 1000 // Initial delay of 1 second
}
}
});
// Worker to process jobs from the emailQueue
worker = new Worker(
"notificationsEmails",
async (job) => {
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: recipient, // Single email address
subject,
type: "text",
text: body
});
logger.logger.debug(`Email job ${job.id} processed successfully`);
},
{
connection: pubClient,
prefix: "{BULLMQ}",
concurrency: 2, // Process up to 2 jobs concurrently
limiter: {
max: 10, // Maximum of 10 jobs per minute
duration: 60 * 1000 // 1 minute
}
}
);
// Worker event handlers
worker.on("completed", (job) => {
logger.logger.debug(`Job ${job.id} completed`);
});
worker.on("failed", (job, err) => {
logger.logger.error(`Job ${job.id} failed: ${err.message}`, { error: err });
});
worker.on("error", (err) => {
logger.logger.error("Worker error:", { error: err });
});
// Graceful shutdown handler for the worker
const shutdown = async () => {
if (worker) {
logger.logger.info("Closing email queue worker...");
await worker.close();
logger.logger.info("Email queue worker closed");
}
};
process.on("SIGTERM", shutdown); // Handle termination signal
process.on("SIGINT", shutdown); // Handle interrupt signal (e.g., Ctrl+C)
}
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` wasnt called).
*/
const getQueue = () => {
if (!emailQueue) {
throw new Error("Email queue not initialized. Ensure loadEmailQueue is called during bootstrap.");
}
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;
// 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}`);
}
};
module.exports = { loadEmailQueue, getQueue, dispatchEmailsToQueue };