UNPKG

@fellas/adonisjs-resque

Version:
217 lines (214 loc) 6.66 kB
import { importAllJobs } from "../chunk-NKW4PRQD.js"; import { getConfig } from "../chunk-MZLOY7HF.js"; import "../chunk-ASV6JZ7C.js"; import { getConnection } from "../chunk-5SDUSZZN.js"; import { __decorateClass } from "../chunk-EUXUH3YW.js"; // commands/resque_start.ts import { BaseCommand, flags } from "@adonisjs/core/ace"; import { createWorker, createMultiWorker, isMultiWorkerEnabled } from "@fellas/adonisjs-resque/services/main"; // scheduler.ts import { Scheduler } from "node-resque"; import Cron from "croner"; import ms from "ms"; function createScheduler() { return new Scheduler({ connection: getConnection() }); } async function startJobSchedules(resqueScheduler, jobs) { const intervals = []; const isLeader = () => { return resqueScheduler.leader; }; const createCronerFor = (job) => { if (job.cron) { return Cron(job.cron, async () => { if (isLeader()) { return await job.enqueue(); } }); } }; const createRepeaterFor = (job) => { if (!job.interval) { return; } let milliseconds; if (typeof job.interval === "number") { milliseconds = job.interval; } else { milliseconds = ms(job.interval); } const intervalId = setInterval(async () => { if (isLeader()) { await job.enqueue(); } }, milliseconds); return intervalId; }; for (const { job } of Object.values(jobs)) { const croner = createCronerFor(job); if (croner) { intervals.push(croner); } const intervalId = createRepeaterFor(job); if (intervalId) { intervals.push(intervalId); } } return intervals; } function cancelSchedules(intervals) { if (!intervals) { return; } for (const inteval of intervals) { if (inteval instanceof Cron) { inteval.stop(); } else { clearInterval(inteval); } } } // commands/resque_start.ts var ResqueStart = class extends BaseCommand { static commandName = "resque:start"; static description = "Start workers / schedules for resque"; static options = { startApp: true, staysAlive: true }; intervals; workerInstance; schedulerInstance; async run() { const pid = process.pid; const jobs = await importAllJobs(); const emitter = await this.app.container.make("emitter"); const verbose = this.verbose ?? getConfig("verbose"); if (this.worker) { const queueNames = this.queueName ?? getConfig("queueNameForWorkers").split(",").map((value) => value.trim()).filter((value) => value !== ""); const isMultiWorker = this.isMulti ?? isMultiWorkerEnabled(); if (isMultiWorker) { this.workerInstance = createMultiWorker(jobs, queueNames); this.logger.info(`Resque multiWorker:${pid} started with ${Object.keys(jobs).length} jobs`); this.workerInstance.on("failure", (workerId, queue, job, failure, duration) => { if (verbose) this.logger.info(`Job ${job.class} in queue ${queue} failed on worker ${workerId} in ${duration}ms`); emitter.emit("resque:failure", { workerId, queue, job: jobs[job.class], failure, duration, args: job.args, pluginOptions: job.pluginOptions }); }); this.workerInstance.on("cleaning_worker", (workerId, _worker, pid2) => { if (verbose) this.logger.info(`Worker ${workerId} (PID ${pid2}) cleaning up...`); }); this.workerInstance.on("end", (workerId) => { if (verbose) this.logger.info(`Worker ${workerId} ended.`); }); this.workerInstance.on("success", (workerId, queue, job, result, duration) => { if (verbose) this.logger.success(`Job ${job.class} in queue ${queue} completed on worker ${workerId} in ${duration}ms, result: ${JSON.stringify(result)}`); }); } else { this.workerInstance = createWorker(jobs, queueNames); this.workerInstance.on("failure", (queue, job, failure, duration) => { if (verbose) this.logger.info(`Job ${job.class} in queue ${queue} failed in ${duration}ms`); emitter.emit("resque:failure", { queue, job: jobs[job.class], failure, duration, args: job.args, pluginOptions: job.pluginOptions }); }); this.workerInstance.on("success", (queue, job, result, duration) => { if (verbose) this.logger.success(`Job ${job.class} in queue ${queue} completed in ${duration}ms, result: ${JSON.stringify(result)}`); }); await this.workerInstance.connect(); } await this.workerInstance.start(); } const runScheduler = getConfig("runScheduler"); if (this.schedule ?? runScheduler) { this.schedulerInstance = createScheduler(); await this.schedulerInstance.connect(); await this.schedulerInstance.start(); this.schedulerInstance.on("end", () => { if (verbose) this.logger.info(`Scheduler ended.`); }); this.intervals = await startJobSchedules(this.schedulerInstance, jobs); if (verbose) this.logger.info(`Scheduler:${pid} started`); } } prepare() { const isVerbose = this.verbose ?? getConfig("verbose"); const terminate = async (signal) => { if (isVerbose) this.logger.info("Receive " + signal); await this.terminate(); }; const cleanup = async () => { this.logger.info("Resque worker terminating..."); if (this.workerInstance) { await this.workerInstance.end(); } if (this.schedulerInstance) { await this.schedulerInstance.end(); } cancelSchedules(this.intervals); }; this.app.listen("SIGINT", terminate).listen("SIGTERM", terminate); this.app.terminating(cleanup); } }; __decorateClass([ flags.boolean({ description: "start job schedule" }) ], ResqueStart.prototype, "schedule", 2); __decorateClass([ flags.boolean({ description: "start workers", default: true }) ], ResqueStart.prototype, "worker", 2); __decorateClass([ flags.boolean({ description: "multi workers" }) ], ResqueStart.prototype, "isMulti", 2); __decorateClass([ flags.boolean({ description: "enable log verbose" }) ], ResqueStart.prototype, "verbose", 2); __decorateClass([ flags.array({ description: "queue names for worker to listen" }) ], ResqueStart.prototype, "queueName", 2); export { ResqueStart as default }; //# sourceMappingURL=resque_start.js.map