UNPKG

torotask

Version:

Task queue processing in NodeJS based on BullMQ and Redis

133 lines 5.73 kB
import { Queue } from 'bullmq'; // Import JobsOptions import { TaskJob } from './job.js'; import { convertJobOptions } from './utils/convert-job-options.js'; export class TaskQueue extends Queue { taskClient; logger; constructor(taskClient, name, options) { if (!taskClient) { throw new Error('ToroTask instance is required.'); } if (!name) { throw new Error('Queue name is required.'); } options = options || {}; options.prefix = options.prefix || taskClient.queuePrefix; options.connection = options.connection = taskClient.getQueueConnectionOptions(); // Use shared Redis instance for queue connection reusing if enabled const sharedQueueRedisInstance = taskClient.getSharedQueueRedisInstance(); if (sharedQueueRedisInstance) { options.connection = sharedQueueRedisInstance; } super(name, options); this.taskClient = taskClient; this.logger = options.logger || taskClient.logger.child({ taskQueue: name }); } /** * Overrides the default BullMQ `Job` class with the custom `TaskJob` class. * This ensures that jobs created and retrieved from this queue are instances of `TaskJob`, * providing access to custom properties and methods. * * @returns The `TaskJob` class constructor. */ get Job() { return TaskJob; } get TaskJob() { return TaskJob; } /** * Get the Redis client instance used by the queue. * @returns The Redis client instance. */ async getRedisClient() { return this.client; } /** * Core logic to add a job to the queue. * Public method intended for use by subclasses or related classes (e.g., SubTask). */ async add(name, payload, options, state) { // Return specific TaskJob const data = { payload, state, }; // Convert options with payload to resolve idFromPayload callbacks const convertedOptions = convertJobOptions(options, payload); const job = await super.add(name, data, convertedOptions); // Cast the result from the base Job to the specific TaskJob return job; } /** * Core logic to add multiple jobs to the queue. * Public method intended for use by subclasses or related classes (e.g., SubTask). */ // Assuming BulkJob's options are compatible with BullMQ's BulkJobOptions async addBulk(jobs) { this.logger.debug(`Bulk adding jobs ${jobs.length} to queue [${this.name}]`); const bulkJobs = jobs.map((job) => { const data = { ...job.data, }; if (job.payload) { data.payload = job.payload; } if (job.state) { data.state = job.state; } // Convert options with payload to resolve idFromPayload callbacks const convertedOptions = convertJobOptions(job.options, data.payload); return { name: job.name, opts: convertedOptions, data, }; }); const result = await super.addBulk(bulkJobs); this.logger.debug(`${result.length} Jobs bulk added added to queue [${this.name}]`); return result; } /** * Core logic to add a job and wait for its completion. * Public method intended for use by subclasses or related classes. */ async _runJobAndWait(name, payload, options, state) { // Use specific JobReturn generic const waitLogger = this.logger.child({ jobName: name, action: 'runAndWait' }); waitLogger.debug({ payload, options }, 'Adding job and waiting for completion'); // Call the corrected _runJob const job = await this.add(name, payload, options, state); // Cast data if needed const jobLogger = this.logger.child({ jobId: job.id, jobName: name }); try { jobLogger.debug('Waiting for job completion...'); // Make sure queueEvents is accessible (might need to be passed or stored) // Assuming this.queueEvents exists similar to BaseQueue/WorkerQueue if (!this.queueEvents) { throw new Error('QueueEvents instance not available for waiting.'); } await job.waitUntilFinished(this.queueEvents); if (!job.id) { jobLogger.error('Job ID is missing after waiting. Cannot get result.'); throw new Error('Job ID is missing after waiting. Cannot get result.'); } jobLogger.debug('Refetching job after completion'); // Use the overridden this.Job getter which returns TaskJob const finishedJob = await this.Job.fromId(this, job.id); if (!finishedJob) { jobLogger.error('Failed to refetch job after completion.'); throw new Error(`Failed to refetch job ${job.id} after completion.`); } jobLogger.debug({ returnValue: finishedJob.returnvalue }, 'Job completed successfully'); return finishedJob.returnvalue; } catch (error) { jobLogger.error({ err: error instanceof Error ? error : new Error(String(error)) }, 'Job failed or could not be waited for'); throw error; } } // Add queueEvents property if it's needed by _runJobAndWait and not already present // You might need to initialize this in the constructor similar to WorkerQueue queueEvents; // Replace 'any' with the actual type, e.g., TaskQueueEvents } //# sourceMappingURL=queue.js.map