UNPKG

n8n

Version:

n8n Workflow Automation Tool

158 lines 8.79 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.WorkflowPublicationApplier = void 0; const backend_common_1 = require("@n8n/backend-common"); const db_1 = require("@n8n/db"); const di_1 = require("@n8n/di"); const ensure_error_1 = require("@n8n/utils/errors/ensure-error"); const trigger_diff_1 = require("../../workflows/publication/trigger-diff"); const workflow_trigger_activator_1 = require("../../workflows/triggers/workflow-trigger-activator"); const workflow_published_data_service_1 = require("../../workflows/workflow-published-data.service"); let WorkflowPublicationApplier = class WorkflowPublicationApplier { constructor(logger, workflowRepository, workflowHistoryRepository, workflowPublishedVersionRepository, workflowTriggerActivator, workflowPublishedDataService) { this.logger = logger; this.workflowRepository = workflowRepository; this.workflowHistoryRepository = workflowHistoryRepository; this.workflowPublishedVersionRepository = workflowPublishedVersionRepository; this.workflowTriggerActivator = workflowTriggerActivator; this.workflowPublishedDataService = workflowPublishedDataService; this.logger = this.logger.scoped('workflow-publication'); } async apply(record) { const { workflow, oldVersion, newVersion } = await this.resolveVersions(record); if (!workflow) return { type: 'skipped', reason: 'workflow-not-found' }; if (workflow.activeVersionId === null) { return await this.unpublish(workflow, oldVersion, record); } if (!newVersion) return { type: 'version-missing' }; return await this.publish(workflow, oldVersion, newVersion, record); } async publish(workflow, oldVersion, newVersion, record) { const oldTriggerNodes = this.workflowTriggerActivator.getEnabledTriggerNodes(oldVersion); const desiredTriggerNodes = this.workflowTriggerActivator.getEnabledTriggerNodes(newVersion); const triggerKinds = this.workflowTriggerActivator.getTriggerKinds(desiredTriggerNodes); const { toAdd, toRemove } = (0, trigger_diff_1.computeTriggerDiff)(oldTriggerNodes, desiredTriggerNodes); this.logger.debug(`Calculated trigger diff for workflow publication: ${toAdd.size} to add, ${toRemove.size} to remove`, { workflowId: record.workflowId, publishedVersionId: record.publishedVersionId, toAdd: Array.from(toAdd), toRemove: Array.from(toRemove), }); this.workflowTriggerActivator .getUnregisteredNonWebhookTriggerNodeIds(record.workflowId, desiredTriggerNodes) .forEach((nodeId) => toAdd.add(nodeId)); const nodesWithUnregisteredWebhooks = await this.workflowTriggerActivator.getNodesWithUnregisteredWebhooks(workflow, newVersion); nodesWithUnregisteredWebhooks.forEach((nodeId) => toAdd.add(nodeId)); if (toAdd.size === 0 && toRemove.size === 0) { await this.advancePublishedVersion(record); return { type: 'completed', triggerStatuses: this.buildTriggerStatuses(desiredTriggerNodes, triggerKinds, { activated: [], failures: [], }), }; } if (toRemove.size > 0 && oldVersion) { await this.workflowTriggerActivator.deactivate(workflow, oldVersion, toRemove); } await this.advancePublishedVersion(record); try { if (toAdd.size > 0) { const outcome = await this.workflowTriggerActivator.activate(workflow, newVersion, toAdd); return this.classifyActivationOutcome(outcome, desiredTriggerNodes, triggerKinds); } if (toRemove.size > 0) { await this.workflowTriggerActivator.updateTriggerCount(workflow, newVersion); } } catch (e) { return { type: 'failed', error: (0, ensure_error_1.ensureError)(e) }; } return { type: 'completed', triggerStatuses: this.buildTriggerStatuses(desiredTriggerNodes, triggerKinds, { activated: [], failures: [], }), }; } async unpublish(workflow, oldVersion, record) { const toRemove = new Set(this.workflowTriggerActivator.getEnabledTriggerNodes(oldVersion).map((node) => node.id)); if (oldVersion && toRemove.size > 0) { await this.workflowTriggerActivator.deactivate(workflow, oldVersion, toRemove); } await this.workflowPublishedDataService.invalidateCache(record.workflowId); await this.workflowPublishedVersionRepository.removePublishedVersion(record.workflowId); return { type: 'unpublished' }; } classifyActivationOutcome(outcome, desiredTriggerNodes, triggerKinds) { const triggerStatuses = this.buildTriggerStatuses(desiredTriggerNodes, triggerKinds, outcome); if (outcome.failures.length === 0) return { type: 'completed', triggerStatuses }; const hasRunningTrigger = triggerStatuses.some((s) => s.status === 'activated'); if (!hasRunningTrigger) { return { type: 'failed', error: this.toActivationError(outcome.failures), triggerStatuses }; } return { type: 'partial', triggerStatuses }; } buildTriggerStatuses(desiredTriggerNodes, triggerKinds, outcome) { const failureByNodeId = new Map(outcome.failures.map((f) => [f.nodeId, f])); return desiredTriggerNodes.map((node) => { const triggerKind = triggerKinds.get(node.id) ?? 'persisted'; const failure = failureByNodeId.get(node.id); return failure ? { nodeId: node.id, nodeName: node.name, status: 'failed', triggerKind, errorMessage: failure.error.message, } : { nodeId: node.id, nodeName: node.name, status: 'activated', triggerKind }; }); } toActivationError(failures) { if (failures.length === 1) return failures[0].error; const detail = failures .map((failure) => `"${failure.nodeName}": ${failure.error.message}`) .join('; '); return new Error(`Triggers failed to activate: ${detail}`); } async resolveVersions(record) { const [workflow, currentlyPublishedVersion, newVersion] = await Promise.all([ this.workflowRepository.findOneBy({ id: record.workflowId }), this.workflowPublishedVersionRepository.findOne({ where: { workflowId: record.workflowId }, relations: { publishedVersion: true }, loadEagerRelations: false, }), this.workflowHistoryRepository.findOneBy({ versionId: record.publishedVersionId }), ]); const oldVersion = currentlyPublishedVersion?.publishedVersion ?? null; return { workflow, oldVersion, newVersion }; } async advancePublishedVersion(record) { await this.workflowPublishedDataService.invalidateCache(record.workflowId); await this.workflowPublishedVersionRepository.setPublishedVersion(record.workflowId, record.publishedVersionId); await this.workflowPublishedDataService.refreshCache(record.workflowId); } }; exports.WorkflowPublicationApplier = WorkflowPublicationApplier; exports.WorkflowPublicationApplier = WorkflowPublicationApplier = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, db_1.WorkflowRepository, db_1.WorkflowHistoryRepository, db_1.WorkflowPublishedVersionRepository, workflow_trigger_activator_1.WorkflowTriggerActivator, workflow_published_data_service_1.WorkflowPublishedDataService]) ], WorkflowPublicationApplier); //# sourceMappingURL=workflow-publication-applier.js.map