@cavai/adonis-queue
Version:
> Basic AdonisJS queue provider
149 lines (148 loc) • 5.23 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueueManager = void 0;
const superjson_1 = __importDefault(require("superjson"));
/**
* Config for manager looks like this
*
* {
* default: 'somename',
* queues: {
* somename: () => new DatabaseDrive({
* table_name: 'sjdasjk',
* })
* }
* }
*/
class QueueManager {
constructor(config, logger, jobsRoot) {
this.config = config;
this.logger = logger;
this.jobsRoot = jobsRoot;
// Setup default driver
this.driver = this.use(config.default);
this.logger.level = config.logLevel || logger.level;
}
use(queue) {
if (!this.config.queues[queue]) {
throw Error(`Queue not defined: "${String(queue)}"`);
}
return this.config.queues[queue]();
}
/**
* Starts up given queue jobs execution
*
* @param queue Queue name to start
*/
async start(queue) {
/**
* Just log errors, but don't stop at any
* In case of error, will keep queue process alive
* Trying to execute next job in-line even after failure
*/
try {
if (this.use(queue).pollingDelay) {
/**
* Will keep queue running and checking for jobs infinitely
*/
// eslint-disable-next-line no-constant-condition
while (true) {
await this.execute();
// Wait before next execution loop
await new Promise((res) => setTimeout(() => res(true), this.use(queue).pollingDelay));
}
}
else {
await this.execute();
}
}
catch (error) {
// Check if it's needed in first place
this.logger.error(error);
}
}
/**
* Executes next job in queue
*/
async execute() {
let job = await this.driver.getNext();
// No job queued, continue with life
if (!job) {
this.logger.debug('No jobs in queue');
return;
}
this.logger.debug({ job }, 'Execution started');
/**
* Dynamically import job class on the fly
* Node stores all imported classes in-memory
* so queue has to be restarted if there has been
* any change to already imported job class
*/
let payload = superjson_1.default.parse(job.payload);
let jobPath = `${this.jobsRoot}/${job.class_path}`;
const JobClass = (await Promise.resolve(`${jobPath}`).then(s => __importStar(require(s)))).default;
const jobClassInstance = new JobClass(...payload.data);
/**
* Wrap handler to try-catch
* it's just to deal with execution failures
* Other cases are handled in parent Ace command
*/
try {
job.attempts++;
await jobClassInstance.handle();
// After execution remove job from queue
await this.driver.remove(job.id);
}
catch (error) {
this.logger.error(error, 'Job execution failed');
/**
* Check if job has depleted retries
* if so, then mark it as failed
*/
if (job.attempts >= JobClass.retries) {
this.logger.error(`Job ${job.id} failed for last time after ${JobClass.retries} retries`);
await this.driver.markFailed(job);
return;
}
await this.driver.reSchedule(job, JobClass.retryAfter);
}
this.logger.debug({ job }, 'Executed successfully');
}
/**
* Stores job to queue for future execution
*
* @param path Path to class file
* @param payload Job payload
* @param options Store options
*/
async store(path, payload, options) {
return this.driver.store(path, payload, options);
}
}
exports.QueueManager = QueueManager;