UNPKG

queue-manager-pro

Version:

A flexible, TypeScript-first queue/task manager with pluggable backends ,dynamic persistence storage and event hooks.

301 lines (217 loc) 9.64 kB
# queue-manager-pro --- A flexible, type-safe, and extensible task queue for Node.js and TypeScript. Supports in-memory, file-based,redis , postgres and custom persistent backends. Features handler registration, event-driven lifecycle, retries, priorities, and graceful worker management. --- ## Features - **Pluggable storage**: in-memory, file,redis, postgres or custom repositories - **Event-driven**: listen to task lifecycle events - **Retries, priorities, stuck task detection** - **Type-safe task and payload binding** via TypeScript generics - **Singleton or multi-instance** queue management - **Atomic dequeue for multi-process setups** --- > **Notice:** > Versions prior to `v1.0.12` are no longer actively maintained. > **_To stay up to date, simply upgrade to the latest release._** > _No other actions or code changes are required—just update your package version for the best > experience._ --- <!-- ## 🚧 Project Status: Actively Improving > **Note:** > This library is currently under active development and continuous improvement. > We encourage you to regularly update to the latest version to benefit from enhancements and > fixes. > **At this stage, updates are not expected to introduce breaking changes or impact your existing > usage.** > > Please feel free to upgrade frequently. Once the API or functionality stabilizes, we will add a > special notice here. --> ## Installation ```bash npm install queue-manager-pro ``` --- ## Quick Start ### 1. Define Your Handlers ```typescript const handlers = { sendEmail: async ({ email }: { email: string }) => { // ...send email logic }, resizeImage: async ({ imageUrl }: { imageUrl: string }) => { // ...resize logic }, }; ``` ### 2. Create a Queue Instance ```typescript import { QueueManager } from 'queue-manager-pro'; const queue = QueueManager.getInstance<typeof handlers>({ backend: { type: 'file', filePath: './tasks.json' }, // or 'memory' /'redis' / 'postgres' / 'custom' }); ``` ### 3. Register Handlers ```typescript // optional options will override instance `maxRetries` and `maxProcessingTime` for the particular handler queue.register('sendEmail', handlers.sendEmail, { maxRetries: 3, maxProcessingTime: 5000 }); queue.register('resizeImage', handlers.resizeImage); ``` ### 4. Add Tasks ```typescript await queue.addTaskToQueue('resizeImage', { imageUrl: 'https://...' }); // task options are optional but strongest , they will override the handler options await queue.addTaskToQueue( 'sendEmail', { email: 'test@example.com' }, { maxProcessingTime: 5000, maxRetries: 3, priority: 3 } ); ``` ### 5. Start the Worker ```typescript queue.startWorker(); ``` ## API Reference ### `QueueManager.getInstance(options)` - **Options:** - `backend`: `{ type: 'file' | 'memory' | 'postgres' | 'redis'| 'custom', ... }` instances , each backend type has its own specific options. - `delay`: Polling interval in ms (default: 10000) - `logger`: Optional logger - support common loggers libraries and 'console' - `singleton`: Use singleton instance (default: true) - `maxRetries`: max retries for tasks that failed or exceeding max processing time could be override by handler or task maxRetries property. (default: 3) - `maxProcessingTime`: max processing time for tasks that stack on processing status too long (default: 10 min) - `crashOnWorkerError`: if `true` it will stop the worker and throw the error (no event emission) else Emit the taskFailed event for external handlers.. (default: false) #### `Storage Backends` - Memory: Fast, non-persistent (lost on restart) - File: local JSON file-based, atomic writes . options: (`filePath:string`) - Redis: using 'ioredis' instance , `{redisClient:Redis, options?:{storageName?:string}}` - Postgres: using 'pg' pool instance , `{pg:pg.Pool , {tableName?:string,schema?:string, useMigrate:boolean}}` - Custom : `CustomQueueRepositoryProps type` (see examples) <!-- - Custom: Plug in your own repository (e.g.MongoDB) - --> **_See [repositories examples](https://github.com/bennyh960/queue-manager/blob/main/examples/repositories.example.md) for usage examples._** --- ### `queue.register(name, handler, options?)` - Register a handler function for a task type. - **Parameters:** - `name`: string Handler name - `handler`: function Handler function `(payload) => any` - `options`(optional): - `maxRetries?` : number - same as the instance 'maxRetries' but it will override the instance 'maxRetries' for the particular handler. - `maxProcessingTime`:number - same as instance 'maxProcessingTime' but it will override the instance 'maxProcessingTime' for the particular handler. - `useAutoSchema?`:boolean - using regex to identify handler params - cover 90% of cases . - `paramSchema?` : a function that get payload as arg , inside you can use your own default schema to validate the payload . (payload:any)=> {isValid:boolean,message:string|null , source:string} **_See [register](https://github.com/bennyh960/queue-manager/blob/main/examples/handlerRegister.md) for usage examples._** --- ### `queue.addTaskToQueue(handler, payload, options?)` Add a new task to the queue. - **Parameters:** - `handler`: string Name of the registered handler - `payload`: object args for the handler (type-checked) - `options`: `{ maxRetries?: number, maxProcessingTime?: number, priority?: number,skipOnPayloadError?:boolean }` (optional) - `maxRetries`: you can set this value for particular task and it will ignore handler and instance maxRetries - `maxProcessingTime` : same as maxRetries , you can specify maxProcessingTime for this particular task if you expect this specific task might take longer/shorter then handler/instance maxProcessingTime - `priority` : the queue is design for 'FIFO' , but if you specify priority for a task it will process the higher priority first. - `skipOnPayloadError` : if it `true` , it will just warn you if payload is not valid but continue. else if it `false` it will kill the process and u get runtime error. - `extraTaskProps`: (optional) - allow you register more properties in your task record. (Not supported yet on postgres) - **Returns:** `Promise<Task>` --- ### `queue.startWorker(concurrency = 1)` - Start processing tasks with the specified concurrency. - **Parameters:** - `concurrency`: number (default: 1) --- ### `queue.stopWorker()` - Gracefully stop all workers. --- ### `queue.on(event, listener)` - Listen to task lifecycle events. - **Events:** - `taskAdded`, `taskStarted`, `taskCompleted`, `taskFailed`, `taskRetried`, `taskRemoved`, `taskStuck` - **Example:** ```typescript queue.on('taskCompleted', task => { console.log('Task completed:', task); }); ``` --- ### More API methods #### `queue.getAllTasks(status?)` - Inspect all current tasks if status is undefined else inspect all tasks with specified status. #### `queue.getTaskById(id)` - inspect task by id #### `queue.updateTask(id,updatedProperties)` - update specific task - updatedProperties - (Partial<Task<handlerMap>>) the fields to update #### `queue.removeTask(id,hardDelete?)` - delete task by id - hardDelete (boolean, default:false) - if true it will remove the task permanently , else the status will be 'deleted' ### `Type Safety` - Handlers and payloads are type-checked. - Task shape is inferred from your handler signatures. <!-- ### More Examples: - custom repository - redis repository - postgres repository --> --- ## Events You can listen to various lifecycle events emitted by the queue instance: | Event | Listener Signature | Description | | ------------- | ------------------ | ------------------------------------------- | | taskAdded | (task) | Fired when a new task is added | | taskStarted | (task) | Fired when a task starts processing | | taskCompleted | (task) | Fired when a task completes successfully | | taskFailed | (task, error) | Fired when a task handler throws an error | | taskRetried | (task) | Fired when a task is retried | | taskRemoved | (task) | Fired when a task is removed from the queue | | taskStuck | (task) | Fired when a task is detected as stuck | **Example:** ```typescript queue.on('taskCompleted', task => { console.log('Task completed:', task); }); ``` --- ## Advanced - **Graceful Shutdown:** Use `await queue.stopWorker()` to gracefully stop all workers and ensure no tasks are left in an inconsistent state. - **Inspect Handlers:** Call `queue.inspectHandler('handlerName')` to retrieve metadata and configuration details about a registered handler. - **Custom Logger:** Provide a custom logger by passing a `LoggerLike` object to the `logger` option when initializing the queue. This allows you to integrate with your preferred logging solution. --- ## License MIT --- ## Contributing Pull requests and issues are welcome! If you have suggestions, bug reports, or want to contribute new features, please open an issue or submit a PR. ---