@imqueue/job
Version:
Simple job queue
297 lines (296 loc) • 9.14 kB
TypeScript
/*!
* 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.
*/
import { ILogger, IMessageQueue } from '@imqueue/core';
/**
* Job queues options
*/
export interface JobQueueOptions {
/**
* Name of the job queue. In worker/publisher mode worker and
* publisher must share the same job queue name.
* Mandatory.
*
* @type {string}
*/
name: string;
/**
* Connection params of the queue engine cluster (typically -
* host and port). By default the broker is redis.
* Optional.
*
* @default [{ host: "localhost", port: 6379 }]
* @type {Array<{host: string, port: number}>}
*/
cluster?: {
host: string;
port: number;
}[];
/**
* Message queue username
*
* @type {string}
*/
username?: string;
/**
* Message queue password
*
* @type {string}
*/
password?: string;
/**
* Logger to be used for producing log and error messages.
* Optional.
* By default is console.
*
* @default console
* @type {ILogger}
*/
logger?: ILogger;
/**
* Safe message delivery or not? When safe delivery is enabled (by default)
* queue is processing jobs with guarantied job data delivery. If process
* fails or dies - job data is re-queued for future processing by another
* worker.
* Optional.
*
* @default true
* @type {boolean}
*/
safe?: boolean;
/**
* TTL in milliseconds of the job in worker queue during safe delivery.
* If worker does not finish processing after this TTL - job is re-queued
* for other workers to be processed.
* Optional.
*
* @default 10000
* @type {number}
*/
safeLockTtl?: number;
/**
* Job queue prefix in queue broker.
* Optional.
*
* @default "imq-job"
* @type {string}
*/
prefix?: string;
/**
* Enables/disables verbose logging
*
* @default false
* @type {boolean}
*/
verbose?: boolean;
/**
* Enables/disables extended verbose logging. The output may contain
* sensitive information, so use it with caution. Does not work if a verbose
* option is disabled.
*
* @default false
* @type {boolean}
*/
verboseExtended?: boolean;
}
export interface JobQueuePopHandler<T> {
/**
* Handles popped from a queue job. If it throws error job will be
* re-scheduled with the same delay as it was pushed into queue,
* If it returns positive number it will be treated as new delay to
* re-schedule message in the queue. Normally, if re-schedule is not needed
* it should return nothing (undefined, void return).
* If worker goes down during the job processing, job will be re-scheduled
* after configured by options safeLockTtl.
*
* @example
* ```typescript
* // job logged and not re-scheduled (normal typical job processing)
* queue.onPop(job => {
* console.log(job);
* });
* // job logged and re-schedule immediately
* queue.onPop(job => {
* console.log(job);
* return 0;
* });
* // job logged and not re-scheduled (normal typical job processing)
* queue.onPop(job => {
* console.log(job);
* return -1;
* });
* // job re-scheduled with the initial delay (job throws)
* queue.on(job => {
* throw new Error('Job error');
* });
* // job re-scheduled with new delay of 1 second
* queue.onPop(job => {
* console.log(job);
* return 1000; // re-run after 1 second
* });
* ```
*
* @param {T} job
* @return {Promise<number | void>}
*/
(job: T): number | void | Promise<number | void>;
}
export interface PushOptions {
/**
* Delay before message to be processed by workers
*/
delay?: number;
/**
* Time to live for message in queue in milliseconds
*/
ttl?: number;
}
export interface AnyJobQueue<T> {
name: string;
readonly logger: ILogger;
start(): Promise<T>;
stop(): Promise<T>;
destroy(): Promise<void>;
}
export interface AnyJobQueueWorker<T, U> {
onPop(handler: JobQueuePopHandler<U>): T;
}
export interface AnyJobQueuePublisher<T, U> {
push(job: U, options?: PushOptions): T;
}
/**
* Abstract job queue, handles base implementations of AnyJobQueue interface.
*/
export declare abstract class BaseJobQueue<T, U> implements AnyJobQueue<T> {
protected options: JobQueueOptions;
protected imq: IMessageQueue;
protected handler: JobQueuePopHandler<U>;
readonly logger: ILogger;
protected constructor(options: JobQueueOptions);
/**
* Full name of this queue
*
* @type {string}
*/
get name(): string;
/**
* Starts processing job queue
*
* @return {Promise<T>} - this queue
*/
start(): Promise<T>;
/**
* Stops processing job queue
*
* @return {Promise<T>} - this queue
*/
stop(): Promise<T>;
/**
* Destroys job queue
*
* @return {Promise<void>}
*/
destroy(): Promise<void>;
}
/**
* Implements simple scheduled job queue publisher. Job queue publisher is only
* responsible for pushing queue messages.
*/
export declare class JobQueuePublisher<T> extends BaseJobQueue<JobQueuePublisher<T>, T> implements AnyJobQueuePublisher<JobQueuePublisher<T>, T> {
/**
* Constructor. Instantiates new JobQueue instance.
*
* @constructor
* @param {JobQueueOptions} options
*/
constructor(options: JobQueueOptions);
/**
* 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: T, options?: PushOptions): JobQueuePublisher<T>;
}
/**
* Implements simple scheduled job queue worker. Job queue worker is only
* responsible for processing queue messages.
*/
export declare class JobQueueWorker<T> extends BaseJobQueue<JobQueueWorker<T>, T> implements AnyJobQueueWorker<JobQueueWorker<T>, T> {
/**
* Constructor. Instantiates new JobQueue instance.
*
* @constructor
* @param {JobQueueOptions} options
*/
constructor(options: JobQueueOptions);
/**
* 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: JobQueuePopHandler<T>): JobQueueWorker<T>;
}
/**
* 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.
*/
export default class JobQueue<T> extends BaseJobQueue<JobQueue<T>, T> implements AnyJobQueueWorker<JobQueue<T>, T>, AnyJobQueuePublisher<JobQueue<T>, T> {
/**
* Constructor. Instantiates new JobQueue instance.
*
* @constructor
* @param {JobQueueOptions} options
*/
constructor(options: JobQueueOptions);
/**
* Starts processing job queue. Throws if handler is not set before start.
*
* @throws {TypeError}
* @return {Promise<T>} - this queue
*/
start(): Promise<JobQueue<T>>;
/**
* 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: T, options?: PushOptions): JobQueue<T>;
/**
* 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: JobQueuePopHandler<T>): JobQueue<T>;
}