UNPKG

adonisjs-jobs

Version:

Job processing for AdonisJS

103 lines (102 loc) 4.34 kB
import { Worker as BullWorker } from 'bullmq'; import * as devalue from 'devalue'; import { REVIVERS } from './devalue.js'; export class Worker { app; config; workers = []; constructor(app, config = { queues: [], concurrency: 1 }) { this.app = app; this.config = config; } async start() { const config = this.app.config.get('jobs', {}); const logger = await this.app.container.make('logger'); const jobs = await this.app.container.make('jobs.list'); const queues = this.config.queues && this.config.queues.length ? this.config.queues : config.queue.split(','); const workers = []; const revivers = { ...REVIVERS, ...(config.serialization?.revivers || {}), }; this.app.terminating(async () => { await Promise.allSettled(workers.map((worker) => worker.close())); }); for (const [index, queueName] of queues.entries()) { let concurrency = Array.isArray(this.config.concurrency) ? (this.config.concurrency[index] ?? this.config.concurrency[0] ?? 1) : (this.config.concurrency ?? 1); const worker = new BullWorker(queueName, async (job) => { const jobClass = jobs[job.name]; if (!jobClass) { logger.error(`Cannot find job ${job.name}`); } let instance; try { instance = await this.app.container.make(jobClass); } catch (error) { logger.error(`Cannot instantiate job ${job.name}`); return; } instance.job = job; instance.logger = logger; instance.payload = devalue.parse(job.data, revivers); logger.info({ id: job.id, options: job.opts, payload: instance.payload }, `Job ${job.name} (${job.id}) started`); let result = await instance.handle(instance.payload); logger.info({ id: job.id, options: job.opts, payload: instance.payload }, `Job ${job.name} (${job.id}) finished`); return result; }, { ...(config.workerOptions || {}), connection: config.connection, concurrency, }); worker.on('failed', async (job, error) => { logger.error(error.message, []); if (job && (job.attemptsMade === job.opts.attempts || job.finishedOn)) { const jobClass = jobs[job.name]; if (!jobClass) { logger.error(`Cannot find job ${job.name}`); } let instance; try { instance = await this.app.container.make(jobClass); } catch { logger.error(`Cannot instantiate job ${job.name}`); return; } instance.job = job; instance.logger = logger; instance.payload = devalue.parse(job.data, revivers); await instance.failed?.(error); } }); worker.on('completed', async (job, result) => { if (!job) return; const jobClass = jobs[job.name]; if (!jobClass) { logger.error(`Cannot find job ${job.name}`); } let instance; try { instance = await this.app.container.make(jobClass); } catch { logger.error(`Cannot instantiate job ${job.name}`); return; } instance.job = job; instance.logger = logger; instance.payload = devalue.parse(job.data, revivers); await instance.completed?.(instance.payload, result); }); this.workers.push(worker); } logger.info(`Processing jobs from the ${JSON.stringify(queues)} queues.`); } async stop() { await Promise.allSettled(this.workers.map((w) => w.close())); } }