UNPKG

n8n

Version:

n8n Workflow Automation Tool

242 lines • 10.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkflowPublicationOutboxConsumer = void 0; const backend_common_1 = require("@n8n/backend-common"); const config_1 = require("@n8n/config"); const db_1 = require("@n8n/db"); const decorators_1 = require("@n8n/decorators"); const di_1 = require("@n8n/di"); const n8n_core_1 = require("n8n-core"); const ensure_error_1 = require("@n8n/utils/errors/ensure-error"); const n8n_workflow_1 = require("n8n-workflow"); const event_service_1 = require("../../events/event.service"); const publication_status_reporter_1 = require("../../workflows/publication/publication-status-reporter"); const workflow_publication_lifecycle_lock_1 = require("../../workflows/publication/workflow-publication-lifecycle-lock"); const workflow_publication_applier_1 = require("../../workflows/publication/workflow-publication-applier"); let WorkflowPublicationOutboxConsumer = class WorkflowPublicationOutboxConsumer { constructor(logger, workflowsConfig, errorReporter, outboxRepository, applier, reporter, instanceSettings, lifecycleLock, tracing, eventService) { this.logger = logger; this.workflowsConfig = workflowsConfig; this.errorReporter = errorReporter; this.outboxRepository = outboxRepository; this.applier = applier; this.reporter = reporter; this.instanceSettings = instanceSettings; this.lifecycleLock = lifecycleLock; this.tracing = tracing; this.eventService = eventService; this.isPolling = false; this.isShuttingDown = false; this.activeDrain = null; this.logger = this.logger.scoped('workflow-publication'); } async init() { if (!this.instanceSettings.isLeader) return; this.startPolling(); await this.drainPending(); } startPolling() { if (!this.workflowsConfig.useWorkflowPublicationService || this.isShuttingDown) return; if (this.isPolling) return; this.isPolling = true; this.schedulePollCycle(); this.logger.debug('Started outbox polling'); } stopPolling() { this.isPolling = false; if (this.pollTimeout) { clearTimeout(this.pollTimeout); this.pollTimeout = undefined; this.logger.debug('Stopped outbox polling'); } } async shutdown() { this.isShuttingDown = true; this.stopPolling(); await this.activeDrain; } async wakeUp() { if (!this.workflowsConfig.useWorkflowPublicationService) return; this.startPolling(); await this.drainPending(); } schedulePollCycle() { clearTimeout(this.pollTimeout); if (!this.shouldKeepPolling()) return; this.pollTimeout = setTimeout(async () => { try { await this.pollCycle(); } catch (error) { this.errorReporter.error(error, { shouldBeLogged: true }); } if (this.shouldKeepPolling()) this.schedulePollCycle(); }, this.workflowsConfig.publicationOutboxPollIntervalMs); } async pollCycle() { const processed = await this.drainPending(); if (processed > 1) { this.logger.debug(`Processed ${processed} workflow publication outbox records in this cycle`); } } async drainPending() { if (this.activeDrain) return await this.activeDrain; const drain = this.runDrain(); this.activeDrain = drain; try { return await drain; } finally { this.activeDrain = null; } } async runDrain() { const concurrency = this.workflowsConfig.workflowPublicationConcurrency; return await this.tracing.startSpan({ name: 'Publication outbox drain', op: 'publication.outbox.drain', attributes: { 'n8n.publication.consumer_concurrency': concurrency }, }, async (span) => { let processed = 0; let aborted = false; const runWorker = async () => { while (!aborted && this.shouldKeepPolling()) { const record = await this.outboxRepository.claimNextPendingRecord(); if (!record) break; await this.processRecord(record); processed++; } }; const workerTasks = Array.from({ length: concurrency }, async () => { await runWorker().catch((error) => { aborted = true; throw error; }); }); const results = await Promise.allSettled(workerTasks); const failure = results.find((r) => r.status === 'rejected'); if (failure?.status === 'rejected') throw failure.reason; span.setAttribute('n8n.publication.records_processed', processed); span.setStatus({ code: 1 }); return processed; }); } shouldKeepPolling() { return this.isPolling && !this.isShuttingDown; } async processRecord(record) { await this.tracing.startSpan({ name: 'Publication outbox record', op: 'publication.outbox.process_record', attributes: { ...this.tracing.pickWorkflowAttributes({ id: record.workflowId }), 'n8n.publication.outbox_id': record.id, 'n8n.publication.published_version_id': record.publishedVersionId, }, }, async (span) => { await this.lifecycleLock.runExclusive(record.workflowId, async () => { if (!this.instanceSettings.isLeader) { await this.outboxRepository.returnToPending(record.id); this.logger.debug('Returned publication outbox record to queue: no longer leader', { outboxId: record.id, workflowId: record.workflowId, }); return; } this.logger.debug('Started processing workflow publication outbox record', { outboxId: record.id, workflowId: record.workflowId, publishedVersionId: record.publishedVersionId, }); const startedAt = Date.now(); let result; try { result = await this.applier.apply(record); } catch (error) { const cause = (0, ensure_error_1.ensureError)(error); result = { type: 'failed', error: new n8n_workflow_1.UnexpectedError(`Unexpected: ${cause.message}`, { cause }), }; } let reporterFailed = false; try { await this.reporter.report(record, result); } catch (reportError) { reporterFailed = true; this.errorReporter.error(reportError, { shouldBeLogged: true }); } this.eventService.emit('workflow-publication-outbox-record-processed', { ...this.toOutcomeLabels(result, reporterFailed), durationMs: Date.now() - startedAt, }); this.logger.debug('Finished processing workflow publication outbox record', { outboxId: record.id, workflowId: record.workflowId, result: result.type, }); span.setAttribute('n8n.publication.result', result.type); }); span.setStatus({ code: 1 }); }); } toOutcomeLabels(result, reporterFailed) { if (reporterFailed) return { result: 'failed', reason: 'none' }; switch (result.type) { case 'completed': return { result: 'published', reason: 'none' }; case 'unpublished': return { result: 'unpublished', reason: 'none' }; case 'skipped': return { result: 'skipped', reason: 'workflow_not_found', }; case 'version-missing': return { result: 'failed', reason: 'version_missing' }; case 'partial': return { result: 'partial_success', reason: 'none' }; case 'failed': return { result: 'failed', reason: 'none' }; } } }; exports.WorkflowPublicationOutboxConsumer = WorkflowPublicationOutboxConsumer; __decorate([ (0, decorators_1.OnShutdown)(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], WorkflowPublicationOutboxConsumer.prototype, "shutdown", null); __decorate([ (0, decorators_1.OnPubSubEvent)('workflow-publish-wake-up', { instanceType: 'main', instanceRole: 'leader' }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], WorkflowPublicationOutboxConsumer.prototype, "wakeUp", null); exports.WorkflowPublicationOutboxConsumer = WorkflowPublicationOutboxConsumer = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, config_1.WorkflowsConfig, n8n_core_1.ErrorReporter, db_1.WorkflowPublicationOutboxRepository, workflow_publication_applier_1.WorkflowPublicationApplier, publication_status_reporter_1.PublicationStatusReporter, n8n_core_1.InstanceSettings, workflow_publication_lifecycle_lock_1.WorkflowPublicationLifecycleLock, n8n_core_1.Tracing, event_service_1.EventService]) ], WorkflowPublicationOutboxConsumer); //# sourceMappingURL=workflow-publication-outbox-consumer.js.map