UNPKG

dt-common-device

Version:

A secure and robust device management library for IoT applications

157 lines (156 loc) 6.16 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.QueueManager = void 0; const redis_1 = require("../../db/redis"); const config_1 = require("../../config/config"); class QueueManager { /** * Get or create a BullMQ queue */ static async getOrCreateQueue(queueKey, queues) { if (queues.has(queueKey)) { return queues.get(queueKey); } const { Queue } = await Promise.resolve().then(() => __importStar(require("bullmq"))); const queue = new Queue(queueKey, { connection: (0, redis_1.getRedisClient)(), }); queues.set(queueKey, queue); return queue; } /** * Get or create a BullMQ worker */ static async getOrCreateWorker(queueKey, workers, queues, processor) { if (workers.has(queueKey)) { return workers.get(queueKey); } const { Worker } = await Promise.resolve().then(() => __importStar(require("bullmq"))); const worker = new Worker(queueKey, processor, { connection: (0, redis_1.getRedisClient)(), concurrency: 1, // Process one job at a time for FIFO ordering }); // Setup event listeners worker.on("completed", async (job) => { const propertyId = job.data.body?.propertyId || "unknown"; (0, config_1.getConfig)().LOGGER.info(`Job ${job.id} completed for property ${propertyId}`); // Check if queue is empty and cleanup worker await QueueManager.checkAndCleanupWorker(queueKey, workers, queues); }); worker.on("failed", async (job, err) => { const propertyId = job?.data?.body?.propertyId || "unknown"; (0, config_1.getConfig)().LOGGER.error(`Job ${job?.id} failed for property ${propertyId}:`, err.message); // Check if queue is empty and cleanup worker await QueueManager.checkAndCleanupWorker(queueKey, workers, queues); }); worker.on("error", (err) => { (0, config_1.getConfig)().LOGGER.error("Worker error:", err.message); }); workers.set(queueKey, worker); return worker; } /** * Check if queue is empty and cleanup worker if no jobs are pending */ static async checkAndCleanupWorker(queueKey, workers, queues) { try { const queue = queues.get(queueKey); if (!queue) return; // Check if queue has any waiting, active, or delayed jobs const [waiting, active, delayed] = await Promise.all([ queue.getWaiting(), queue.getActive(), queue.getDelayed(), ]); const totalJobs = waiting.length + active.length + delayed.length; // If no jobs are pending, cleanup the worker if (totalJobs === 0) { const worker = workers.get(queueKey); if (worker) { await worker.close(); workers.delete(queueKey); // Extract propertyId from queueKey (format: propertyId_copilot) const propertyId = queueKey.replace("_copilot", ""); (0, config_1.getConfig)().LOGGER.info(`Worker cleaned up for property ${propertyId} - no pending jobs`); } } } catch (error) { (0, config_1.getConfig)().LOGGER.error(`Error during worker cleanup for ${queueKey}:`, error.message); } } /** * Close all workers and queues */ static async closeAllWorkersAndQueues(workers, queues) { try { // Close all workers and queues await Promise.all([ ...Array.from(workers.values()).map((worker) => worker.close()), ...Array.from(queues.values()).map((queue) => queue.close()), ]); workers.clear(); queues.clear(); (0, config_1.getConfig)().LOGGER.info("All workers and queues closed successfully"); } catch (error) { (0, config_1.getConfig)().LOGGER.error("Error closing workers and queues:", error.message); throw error; } } /** * Generate queue name for a property */ static generateQueueName(propertyId) { return `${propertyId}_copilot`; } /** * Extract property ID from job ID */ static extractPropertyIdFromJobId(jobId) { return jobId.split("-")[0]; } /** * Generate unique job ID */ static generateJobId(propertyId) { return `${propertyId}-${Date.now()}-${Math.random() .toString(36) .substr(2, 9)}`; } } exports.QueueManager = QueueManager;