UNPKG

n8n

Version:

n8n Workflow Automation Tool

226 lines 11 kB
"use strict"; 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.Worker = void 0; const typedi_1 = require("typedi"); const core_1 = require("@oclif/core"); const express_1 = __importDefault(require("express")); const http_1 = __importDefault(require("http")); const n8n_workflow_1 = require("n8n-workflow"); const Db = __importStar(require("../Db")); const ResponseHelper = __importStar(require("../ResponseHelper")); const config_1 = __importDefault(require("../config")); const constants_1 = require("../constants"); const CredentialsOverwrites_1 = require("../CredentialsOverwrites"); const middlewares_1 = require("../middlewares"); const MessageEventBus_1 = require("../eventbus/MessageEventBus/MessageEventBus"); const EventMessageGeneric_1 = require("../eventbus/EventMessageClasses/EventMessageGeneric"); const orchestration_handler_worker_service_1 = require("../services/orchestration/worker/orchestration.handler.worker.service"); const orchestration_worker_service_1 = require("../services/orchestration/worker/orchestration.worker.service"); const service_unavailable_error_1 = require("../errors/response-errors/service-unavailable.error"); const BaseCommand_1 = require("./BaseCommand"); const job_processor_1 = require("../scaling/job-processor"); const log_streaming_event_relay_1 = require("../events/log-streaming-event-relay"); class Worker extends BaseCommand_1.BaseCommand { async stopProcess() { var _a; this.logger.info('Stopping n8n...'); try { await ((_a = this.externalHooks) === null || _a === void 0 ? void 0 : _a.run('n8n.stop', [])); } catch (error) { await this.exitWithCrash('There was an error shutting down n8n.', error); } await this.exitSuccessFully(); } constructor(argv, cmdConfig) { super(argv, cmdConfig); this.needsCommunityPackages = true; if (!process.env.N8N_ENCRYPTION_KEY) { throw new n8n_workflow_1.ApplicationError('Missing encryption key. Worker started without the required N8N_ENCRYPTION_KEY env var. More information: https://docs.n8n.io/hosting/configuration/configuration-examples/encryption-key/'); } this.setInstanceType('worker'); this.setInstanceQueueModeId(); } async init() { const { QUEUE_WORKER_TIMEOUT } = process.env; if (QUEUE_WORKER_TIMEOUT) { this.gracefulShutdownTimeoutInS = parseInt(QUEUE_WORKER_TIMEOUT, 10) || this.globalConfig.queue.bull.gracefulShutdownTimeout; this.logger.warn('QUEUE_WORKER_TIMEOUT has been deprecated. Rename it to N8N_GRACEFUL_SHUTDOWN_TIMEOUT.'); } await this.initCrashJournal(); this.logger.debug('Starting n8n worker...'); this.logger.debug(`Queue mode id: ${this.queueModeId}`); await this.setConcurrency(); await super.init(); await this.initLicense(); this.logger.debug('License init complete'); await this.initBinaryDataService(); this.logger.debug('Binary data service init complete'); await this.initExternalHooks(); this.logger.debug('External hooks init complete'); await this.initExternalSecrets(); this.logger.debug('External secrets init complete'); await this.initEventBus(); this.logger.debug('Event bus init complete'); await this.initScalingService(); await this.initOrchestration(); this.logger.debug('Orchestration init complete'); await typedi_1.Container.get(MessageEventBus_1.MessageEventBus).send(new EventMessageGeneric_1.EventMessageGeneric({ eventName: 'n8n.worker.started', payload: { workerId: this.queueModeId, }, })); } async initEventBus() { await typedi_1.Container.get(MessageEventBus_1.MessageEventBus).initialize({ workerId: this.queueModeId, }); typedi_1.Container.get(log_streaming_event_relay_1.LogStreamingEventRelay).init(); } async initOrchestration() { await typedi_1.Container.get(orchestration_worker_service_1.OrchestrationWorkerService).init(); await typedi_1.Container.get(orchestration_handler_worker_service_1.OrchestrationHandlerWorkerService).initWithOptions({ queueModeId: this.queueModeId, redisPublisher: typedi_1.Container.get(orchestration_worker_service_1.OrchestrationWorkerService).redisPublisher, getRunningJobIds: () => this.jobProcessor.getRunningJobIds(), getRunningJobsSummary: () => this.jobProcessor.getRunningJobsSummary(), }); } async setConcurrency() { const { flags } = await this.parse(Worker); const envConcurrency = config_1.default.getEnv('executions.concurrency.productionLimit'); this.concurrency = envConcurrency !== -1 ? envConcurrency : flags.concurrency; } async initScalingService() { const { ScalingService } = await Promise.resolve().then(() => __importStar(require('../scaling/scaling.service'))); this.scalingService = typedi_1.Container.get(ScalingService); await this.scalingService.setupQueue(); this.scalingService.setupWorker(this.concurrency); this.jobProcessor = typedi_1.Container.get(job_processor_1.JobProcessor); } async setupHealthMonitor() { var _a; const { port } = this.globalConfig.queue.health; const app = (0, express_1.default)(); app.disable('x-powered-by'); const server = http_1.default.createServer(app); app.get('/healthz', async (_req, res) => { this.logger.debug('Health check started!'); const connection = Db.getConnection(); try { if (!connection.isInitialized) { throw new n8n_workflow_1.ApplicationError('No active database connection'); } await connection.query('SELECT 1'); } catch (e) { this.logger.error('No Database connection!', e); const error = new service_unavailable_error_1.ServiceUnavailableError('No Database connection!'); return ResponseHelper.sendErrorResponse(res, error); } try { await this.scalingService.pingQueue(); } catch (e) { this.logger.error('No Redis connection!', e); const error = new service_unavailable_error_1.ServiceUnavailableError('No Redis connection!'); return ResponseHelper.sendErrorResponse(res, error); } const responseData = { status: 'ok', }; this.logger.debug('Health check completed successfully!'); ResponseHelper.sendSuccessResponse(res, responseData, true, 200); }); let presetCredentialsLoaded = false; const endpointPresetCredentials = this.globalConfig.credentials.overwrite.endpoint; if (endpointPresetCredentials !== '') { app.post(`/${endpointPresetCredentials}`, middlewares_1.rawBodyReader, middlewares_1.bodyParser, async (req, res) => { if (!presetCredentialsLoaded) { const body = req.body; if (req.contentType !== 'application/json') { ResponseHelper.sendErrorResponse(res, new Error('Body must be a valid JSON, make sure the content-type is application/json')); return; } typedi_1.Container.get(CredentialsOverwrites_1.CredentialsOverwrites).setData(body); presetCredentialsLoaded = true; ResponseHelper.sendSuccessResponse(res, { success: true }, true, 200); } else { ResponseHelper.sendErrorResponse(res, new Error('Preset credentials can be set once')); } }); } server.on('error', (error) => { if (error.code === 'EADDRINUSE') { this.logger.error(`n8n's port ${port} is already in use. Do you have the n8n main process running on that port?`); process.exit(1); } }); await new Promise((resolve) => server.listen(port, () => resolve())); await ((_a = this.externalHooks) === null || _a === void 0 ? void 0 : _a.run('worker.ready')); this.logger.info(`\nn8n worker health check via, port ${port}`); } async run() { this.logger.info('\nn8n worker is now ready'); this.logger.info(` * Version: ${constants_1.N8N_VERSION}`); this.logger.info(` * Concurrency: ${this.concurrency}`); this.logger.info(''); if (this.globalConfig.queue.health.active) { await this.setupHealthMonitor(); } if (!constants_1.inTest && process.stdout.isTTY) { process.stdin.setRawMode(true); process.stdin.resume(); process.stdin.setEncoding('utf8'); process.stdin.on('data', (key) => { if (key.charCodeAt(0) === 3) process.kill(process.pid, 'SIGINT'); }); } if (!constants_1.inTest) await new Promise(() => { }); } async catch(error) { await this.exitWithCrash('Worker exiting due to an error.', error); } } exports.Worker = Worker; Worker.description = '\nStarts a n8n worker'; Worker.examples = ['$ n8n worker --concurrency=5']; Worker.flags = { help: core_1.Flags.help({ char: 'h' }), concurrency: core_1.Flags.integer({ default: 10, description: 'How many jobs can run in parallel.', }), }; //# sourceMappingURL=worker.js.map