UNPKG

redis-smq

Version:

A high-performance, reliable, and scalable message queue for Node.js.

170 lines 7.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PurgeQueueJob = void 0; const background_job_worker_abstract_js_1 = require("../../../abstract/background-job/background-job-worker-abstract.js"); const redis_smq_common_1 = require("redis-smq-common"); const purge_queue_job_manager_js_1 = require("./purge-queue-job-manager.js"); const index_js_1 = require("../../../index.js"); const _delete_message_js_1 = require("../../../../message-manager/_/_delete-message.js"); const index_js_2 = require("../../../../errors/index.js"); const message_browser_factory_js_1 = require("../../../../queue-messages/message-browser-factory.js"); class PurgeQueueJob extends background_job_worker_abstract_js_1.BackgroundJobWorkerAbstract { constructor() { super(...arguments); this.jobManager = null; } processNextJob(cb) { redis_smq_common_1.async.waterfall([ (cb) => { this.getJobManager().acquireNextJob((err, jobId) => { if (err) return cb(err); if (!jobId) { this.logger.debug(`No job available.`); return cb(null); } this.logger.debug(`Worker ${this.id} acquired job: ${jobId}`); cb(null, jobId); }); }, (jobId, cb) => { this.executeJob(jobId, (err) => { if (err) { this.logger.error(`Job ${jobId} failed:`, err); } else { this.logger.info(`Job ${jobId} completed successfully`); } cb(err); }); }, ], cb); } executeJob(jobId, cb) { const jobManager = this.getJobManager(); redis_smq_common_1.async.waterfall([ (next) => { jobManager.start(jobId, this.id, next); }, (job, next) => { this.purgeMessages(job, next); }, (totalPurged, next) => { jobManager.complete(jobId, { meta: { purged: totalPurged } }, (err) => next(err)); }, ], (err) => { if (err) { return jobManager.fail(jobId, err.message, (err) => { if (!err) { this.logger.debug(`Successfully marked job ${jobId} as failed`); } cb(); }); } cb(); }); } goingUp() { return super.goingUp().concat([ (cb) => { const redisClient = this.getRedisClient(); this.jobManager = new purge_queue_job_manager_js_1.PurgeQueueJobManager(redisClient, this.logger); this.jobManager.initialize(cb); }, ]); } getJobManager() { if (!this.jobManager) throw new redis_smq_common_1.PanicError({ message: 'A PurgeQueueJobManager instance is required.', }); return this.jobManager; } purgeMessages(job, cb) { const parsedParams = job.payload.queue; const delay = job.delay || 5000; const batchSize = job.batchSize || 1000; let totalPurged = 0; let initialTotalItems = 0; let batchCount = 0; this.logger.debug(`Starting batch purge for queue ${parsedParams.queueParams.name}`); const purgeBatch = () => { batchCount += 1; this.logger.debug(`Processing purge batch ${batchCount} (batch size = ${batchSize}) for queue ${parsedParams.queueParams.name}`); redis_smq_common_1.async.waterfall([ (next) => { this.getJobManager().get(job.id, (err, currentJob) => { if (err) { return next(err); } if (!currentJob || currentJob.status === index_js_1.EBackgroundJobStatus.CANCELED) { return next(new index_js_2.BackgroundJobCanceledError({ metadata: { jobId: job.id }, })); } next(); }); }, (_, next) => message_browser_factory_js_1.MessageBrowserFactory.createBrowserForQueue(job.payload.queue.queueParams, job.payload.messageType, this.logger, next), (messageBrowser, next) => { messageBrowser.getMessageIds(parsedParams, 1, batchSize, next); }, (result, next) => { const { items, totalItems } = result; if (batchCount === 1) { initialTotalItems = totalItems; this.logger.debug(`Queue "${parsedParams.queueParams.name}" has ${initialTotalItems} messages to purge`); } if (items.length === 0) { this.logger.debug(`No messages to purge in this batch for queue ${parsedParams.queueParams.name}`); return next(null, false); } this.logger.debug(`Deleting ${items.length} messages from queue ${parsedParams.queueParams.name}`); (0, _delete_message_js_1._deleteMessage)(this.getRedisClient(), items, job.id, (err, reply) => { if (err) { this.logger.error(`Error deleting messages: ${err.message}`); return next(err); } const successfullyDeleted = (reply === null || reply === void 0 ? void 0 : reply.stats.success) || 0; totalPurged += successfullyDeleted; this.logger.debug(`Batch ${batchCount}: Deleted ${successfullyDeleted} messages`); this.getJobManager().updateProgress(job.id, totalPurged, initialTotalItems); const shouldContinue = items.length === batchSize; next(null, shouldContinue); }); }, ], (err, shouldContinue) => { if (err) { this.logger.error(`Error in purge batch: ${err.message}`); return cb(err); } if (shouldContinue) { this.logger.debug(`Got full batch (${batchSize} items), continuing with batch ${batchCount + 1}`); if (delay) setTimeout(() => purgeBatch(), delay); else purgeBatch(); } else { this.logger.info(`Successfully purged ${totalPurged} messages from queue "${parsedParams.queueParams.name}"`); cb(null, totalPurged); } }); }; purgeBatch(); } work(cb) { redis_smq_common_1.async.series([ (cb) => { this.getJobManager().recoverStuckJobs(cb); }, (cb) => { this.processNextJob(cb); }, ], (err) => cb(err)); } } exports.PurgeQueueJob = PurgeQueueJob; exports.default = PurgeQueueJob; //# sourceMappingURL=purge-queue.job.js.map