UNPKG

wakaq

Version:

Background task queue for Node backed by Redis, a super minimal Celery

184 lines (183 loc) 6.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WakaQChildWorker = void 0; const exceptions_js_1 = require("./exceptions.js"); const logger_js_1 = require("./logger.js"); const serializer_js_1 = require("./serializer.js"); class WakaQChildWorker { constructor(wakaq) { this._stopProcessing = false; this._numTasksProcessed = 0; this.wakaq = wakaq; this.logger = (0, logger_js_1.setupLogging)(this.wakaq, true); this.wakaq.logger = this.logger; } async start() { const _this = this; process.on('SIGINT', this._ignoreSignal); process.on('SIGTERM', () => _this._stopFromSigTerm()); process.on('SIGQUIT', () => _this._onSoftTimeout()); process.on('message', this._onMessageFromParent); try { this.logger.debug(`started worker process ${process.pid}`); if (this.wakaq.afterWorkerStartedCallback) await this.wakaq.afterWorkerStartedCallback(); this._numTasksProcessed = 0; while (!this._stopProcessing) { this._sendPingToParent(); const { queueBrokerKey, payload } = (await this._blockingDequeue()) || {}; if (queueBrokerKey !== undefined && payload !== undefined) { const task = this.wakaq.tasks.get(payload.name); if (!task && payload.name) this.logger.error(`Task not found: ${payload.name}`); if (task) { const queue = this.wakaq.queuesByKey.get(queueBrokerKey); this.wakaq.currentTask = task; const retry = payload.retry ?? 0; try { await this._executeTask(task, payload.args, queue); } catch (error) { if (error instanceof exceptions_js_1.SoftTimeout) { const maxRetries = task.maxRetries ?? queue?.maxRetries ?? this.wakaq.maxRetries; if (retry + 1 > maxRetries) { this.logger.error(error); } else { this.logger.warning(error); this.wakaq.enqueueAtEnd(task.name, payload.args, queue, retry); } } else { this.logger.error(error); } } finally { this.wakaq.currentTask = undefined; } } else { this._sendPingToParent(); } } else { this._sendPingToParent(); } if (this.wakaq.maxTasksPerWorker && this._numTasksProcessed >= this.wakaq.maxTasksPerWorker) { this.logger.info(`restarting worker after ${this._numTasksProcessed} tasks`); this._stopProcessing = true; } } } catch (error) { if (error instanceof exceptions_js_1.SoftTimeout) { if (this.wakaq.currentTask !== null) throw error; } else { console.log('got error'); console.log(error); this.logger.error(error); } } finally { this.wakaq.dispose(); process.off('message', this._onMessageFromParent); } } _ignoreSignal() { console.log('Got SIGINT'); } _stopFromSigTerm() { console.log('Got SIGTERM'); this._stop(); } _stop() { console.log('Child exiting'); this._stopProcessing = true; } _onSoftTimeout() { console.log('Got SIGQUIT'); this._stopProcessing = true; throw new exceptions_js_1.SoftTimeout('SoftTimeout'); } async _blockingDequeue() { if (this.wakaq.brokerKeys.length === 0) { this.wakaq.sleep(this.wakaq.waitTimeout); return undefined; } const data = await this.wakaq.broker.blpop(this.wakaq.brokerKeys, this.wakaq.waitTimeout.seconds); if (!data) return undefined; return { queueBrokerKey: data[0], payload: (0, serializer_js_1.deserialize)(data[1]) }; } _sendPingToParent(taskName = '', queueName = '') { const msg = { type: 'wakaq-ping', taskName, queueName, }; if (process.send) { process.send(msg, undefined, undefined, (e) => { if (e) this.logger.warn(e); }); } } async _executeTask(task, args, queue) { this._sendPingToParent(task.name, queue?.name); this.logger.debug(`running with args ${args}`); if (this.wakaq.beforeTaskStartedCallback) this.wakaq.beforeTaskStartedCallback(task); try { await task.fn(...args); } finally { this._sendPingToParent(); this._numTasksProcessed += 1; if (this.wakaq.afterTaskFinishedCallback) this.wakaq.afterTaskFinishedCallback(task); } } async _onMessageFromParent(message) { console.log('_onMessageFromParent'); console.log(message); const payload = (0, serializer_js_1.deserialize)(message); const task = this.wakaq.tasks.get(payload.name); if (!task) { this.logger.error(`Task not found: ${payload.name}`); return; } let retry = 0; this.wakaq.currentTask = task; try { while (true) { try { await this._executeTask(task, payload.payload); break; } catch (error) { if (error instanceof exceptions_js_1.SoftTimeout) { retry += 1; const maxRetries = task.maxRetries ?? this.wakaq.maxRetries; if (retry > maxRetries) { this.logger.error(error); break; } else { this.logger.warning(error); } } else { this.logger.error(error); break; } } } } finally { this.wakaq.currentTask = undefined; } } } exports.WakaQChildWorker = WakaQChildWorker;