UNPKG

@imqueue/job

Version:

Simple job queue

233 lines 7.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JobQueueWorker = exports.JobQueuePublisher = exports.BaseJobQueue = void 0; /*! * Job Queue for @imqueue framework * * I'm Queue Software Project * Copyright (C) 2025 imqueue.com <support@imqueue.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * If you want to use this code in a closed source (commercial) project, you can * purchase a proprietary commercial license. Please contact us at * <support@imqueue.com> to get commercial licensing options. */ const core_1 = require("@imqueue/core"); /** * Abstract job queue, handles base implementations of AnyJobQueue interface. */ class BaseJobQueue { constructor(options) { this.options = options; this.logger = options.logger || console; } /** * Full name of this queue * * @type {string} */ get name() { return this.options.name; } /** * Starts processing job queue * * @return {Promise<T>} - this queue */ async start() { await this.imq.start(); return this; } /** * Stops processing job queue * * @return {Promise<T>} - this queue */ async stop() { await this.imq.stop(); return this; } /** * Destroys job queue * * @return {Promise<void>} */ async destroy() { await this.imq.destroy(); } } exports.BaseJobQueue = BaseJobQueue; /** * Creates and returns IMQOptions derived from a given JobQueueOptions * * @param {JobQueueOptions} options * @param {ILogger} logger * @return {Partial<IMQOptions>} * @private */ function toIMQOptions(options, logger) { return { cluster: options.cluster, cleanup: false, safeDelivery: typeof options.safe === 'undefined' ? true : options.safe, safeDeliveryTtl: typeof options.safeLockTtl === 'undefined' ? 10000 : options.safeLockTtl, prefix: options.prefix || 'imq-job', logger, }; } // noinspection JSUnusedGlobalSymbols /** * Implements simple scheduled job queue publisher. Job queue publisher is only * responsible for pushing queue messages. */ class JobQueuePublisher extends BaseJobQueue { /** * Constructor. Instantiates new JobQueue instance. * * @constructor * @param {JobQueueOptions} options */ constructor(options) { super(options); this.imq = core_1.default.create(options.name, toIMQOptions(options, this.logger), core_1.IMQMode.PUBLISHER); } /** * Pushes new job to this queue * * @param {T} job - job data itself of user defined type * @param {PushOptions} options - push options, like delay and ttl for job * @return {JobQueue<T>} - this queue */ push(job, options) { options = options || {}; this.imq.send(this.name, Object.assign(Object.assign({ job: job }, (options.ttl ? { expire: Date.now() + options.ttl } : {})), (options.delay ? { delay: options.delay } : {})), options.delay).catch(err => this.logger.log('JobQueue push error:', err)); return this; } } exports.JobQueuePublisher = JobQueuePublisher; // noinspection JSUnusedGlobalSymbols /** * Implements simple scheduled job queue worker. Job queue worker is only * responsible for processing queue messages. */ class JobQueueWorker extends BaseJobQueue { /** * Constructor. Instantiates new JobQueue instance. * * @constructor * @param {JobQueueOptions} options */ constructor(options) { super(options); this.imq = core_1.default.create(options.name, toIMQOptions(options, this.logger), core_1.IMQMode.WORKER); } /** * Sets up job handler, which is called when the job is popped from this * queue. * * @param {JobQueuePopHandler<T>} handler - job pop handler * @return {JobQueueWorker<T>} - this queue */ onPop(handler) { this.handler = handler; this.imq.removeAllListeners('message'); this.imq.on('message', async (message) => { const { job, expire, delay } = message; let rescheduleDelay; try { rescheduleDelay = this.handler(job); if (rescheduleDelay && typeof rescheduleDelay === 'object' && rescheduleDelay && rescheduleDelay.then) { // it's promise rescheduleDelay = await rescheduleDelay; } } catch (err) { rescheduleDelay = delay; this.logger.log('Error handling job:', err); } if (typeof expire === 'number' && expire <= Date.now()) { return; // remove job from queue } if (typeof rescheduleDelay === 'number' && rescheduleDelay >= 0) { await this.imq.send(this.name, message, rescheduleDelay); } }); return this; } } exports.JobQueueWorker = JobQueueWorker; // noinspection JSUnusedGlobalSymbols /** * Implements simple scheduled job queue. Job scheduling is optional. It may * process jobs immediately or after specified delay for particular job. * It also allows to define max lifetime of the job in a queue, after which * the job is removed from a queue. * Supports graceful shutdown, if TERM or SIGINT is sent to the process. */ class JobQueue extends BaseJobQueue { /** * Constructor. Instantiates new JobQueue instance. * * @constructor * @param {JobQueueOptions} options */ constructor(options) { super(options); this.imq = core_1.default.create(options.name, toIMQOptions(options, this.logger)); } /** * Starts processing job queue. Throws if handler is not set before start. * * @throws {TypeError} * @return {Promise<T>} - this queue */ async start() { if (!this.handler) { throw new TypeError('Message handler is not set, can not start job queue!'); } return await super.start(); } /** * Pushes new job to this queue. Throws if handler is not set. * * @throws {TypeError} * @param {T} job - job data itself of user defined type * @param {PushOptions} options - push options, like delay and ttl for job * @return {JobQueue<T>} - this queue */ push(job, options) { if (!this.handler) { throw new TypeError('Message handler is not set, can not enqueue data!'); } return JobQueuePublisher.prototype.push.call(this, job, options); } /** * Sets up job handler, which is called when the job is popped from this * queue. * * @param {JobQueuePopHandler<T>} handler - job pop handler * @return {JobQueue<T>} - this queue */ onPop(handler) { return JobQueueWorker.prototype.onPop.call(this, handler); } } exports.default = JobQueue; //# sourceMappingURL=index.js.map