UNPKG

@tsed/bullmq

Version:
116 lines 4.4 kB
import { constant, DIContext, inject, injectable, injectMany, injector, logger, ProviderType, runInContext } from "@tsed/di"; import { getComputedType } from "@tsed/schema"; import { v4 } from "uuid"; import { BullMQTypes } from "./constants/BullMQTypes.js"; import { BULLMQ } from "./constants/constants.js"; import { JobDispatcher } from "./dispatchers/index.js"; import { createQueueProvider } from "./utils/createQueueProvider.js"; import { createWorkerProvider } from "./utils/createWorkerProvider.js"; import { getFallbackJobToken, getJobToken } from "./utils/getJobToken.js"; import { mapQueueOptions } from "./utils/mapQueueOptions.js"; import { mapWorkerOptions } from "./utils/mapWorkerOptions.js"; export class BullMQModule { constructor() { this.dispatcher = inject(JobDispatcher); this.onProcess = async (job) => { const jobService = this.getJob(job.name, job.queueName); if (!jobService) { logger().warn({ event: "BULLMQ_JOB_NOT_FOUND", message: `Job ${job.name} ${job.queueName} not found` }); return; } const $ctx = new DIContext({ id: job.id || v4().split("-").join(""), additionalProps: { logType: "bullmq", name: job.name, queue: job.queueName, attempt: job.attemptsMade } }); $ctx.set("BULLMQ_JOB", job); try { return await runInContext($ctx, () => { $ctx.logger.info("Processing job"); try { return jobService.handle(job.data, job); } finally { $ctx.logger.info("Finished processing job"); } }); } catch (er) { $ctx.logger.error({ event: "BULLMQ_JOB_ERROR", message: er.message, stack: er.stack }); throw er; } finally { await $ctx.destroy(); } }; // build providers allow @Inject(queue) usage in JobController instance if (this.isEnabled()) { const queues = [...this.getUniqQueueNames()]; this.buildQueues(queues); if (!this.isWorkerEnabled()) { const workers = this.config.workerQueues?.length ? this.config.workerQueues : queues; this.buildWorkers(workers); } } } get config() { return constant("bullmq"); } $onInit() { if (this.isEnabled()) { injectMany(BullMQTypes.CRON).map((job) => this.dispatcher.dispatch(getComputedType(job))); } } async $onDestroy() { if (!this.isEnabled()) { return; } await Promise.all(injectMany(BullMQTypes.QUEUE).map((queue) => queue.close())); await Promise.all(injectMany(BullMQTypes.WORKER).map((worker) => worker.close())); } isEnabled() { return !!this.config; } isWorkerEnabled() { return this.config.disableWorker; } buildQueues(queues) { queues.forEach((queue) => { const opts = mapQueueOptions(queue, this.config); createQueueProvider(queue, opts); }); } buildWorkers(workers) { workers.forEach((worker) => { const opts = mapWorkerOptions(worker, this.config); createWorkerProvider(worker, this.onProcess, opts); }); } /** * Auto discover queue names from provider and merge it with queue names from global configuration. * @private */ getUniqQueueNames() { return new Set(injector() .getProviders([BullMQTypes.JOB, BullMQTypes.CRON, BullMQTypes.FALLBACK_JOB]) .map((provider) => provider.store.get(BULLMQ)?.queue) .concat(this.config.queues) .filter(Boolean)); } getJob(name, queueName) { return inject(getJobToken(queueName, name)) || inject(getFallbackJobToken(queueName)) || inject(getFallbackJobToken()); } } injectable(BullMQModule).type(ProviderType.MODULE); //# sourceMappingURL=BullMQModule.js.map