UNPKG

n8n

Version:

n8n Workflow Automation Tool

396 lines 18.3 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 __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 __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); 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.WorkflowExecutionService = void 0; const backend_common_1 = require("@n8n/backend-common"); const config_1 = require("@n8n/config"); const db_1 = require("@n8n/db"); const di_1 = require("@n8n/di"); const n8n_core_1 = require("n8n-core"); const n8n_workflow_1 = require("n8n-workflow"); const execution_data_service_1 = require("../executions/execution-data.service"); const pre_execution_checks_1 = require("../executions/pre-execution-checks"); const node_types_1 = require("../node-types"); const test_webhooks_1 = require("../webhooks/test-webhooks"); const WorkflowExecuteAdditionalData = __importStar(require("../workflow-execute-additional-data")); const workflow_runner_1 = require("../workflow-runner"); let WorkflowExecutionService = class WorkflowExecutionService { constructor(logger, errorReporter, executionRepository, workflowRepository, nodeTypes, testWebhooks, workflowRunner, globalConfig, subworkflowPolicyChecker, executionDataService) { this.logger = logger; this.errorReporter = errorReporter; this.executionRepository = executionRepository; this.workflowRepository = workflowRepository; this.nodeTypes = nodeTypes; this.testWebhooks = testWebhooks; this.workflowRunner = workflowRunner; this.globalConfig = globalConfig; this.subworkflowPolicyChecker = subworkflowPolicyChecker; this.executionDataService = executionDataService; } async runWorkflow(workflowData, node, data, additionalData, mode, responsePromise) { const nodeExecutionStack = [ { node, data: { main: data, }, source: null, }, ]; const executionData = (0, n8n_workflow_1.createRunExecutionData)({ executionData: { nodeExecutionStack, }, }); const runData = { userId: additionalData.userId, executionMode: mode, executionData, workflowData, }; return await this.workflowRunner.run(runData, true, undefined, undefined, responsePromise); } isDestinationNodeATrigger(destinationNode, workflow) { const node = workflow.nodes.find((n) => n.name === destinationNode); if (node === undefined) { return false; } const nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); return nodeType.description.group.includes('trigger'); } async executeManually(payload, user, pushRef) { const workflowIsActive = await this.workflowRepository.isActive(payload.workflowData.id); payload.workflowData.active = false; payload.workflowData.activeVersionId = null; if ('triggerToStartFrom' in payload) { Reflect.deleteProperty(payload, 'runData'); } let data; if (isPartialExecution(payload)) { if (this.partialExecutionFulfilsPreconditions(payload)) { data = { destinationNode: payload.destinationNode, executionMode: 'manual', runData: payload.runData, pinData: payload.workflowData.pinData, pushRef, workflowData: payload.workflowData, userId: user.id, dirtyNodeNames: payload.dirtyNodeNames, agentRequest: payload.agentRequest, }; } else { payload = upgradeToFullManualExecutionFromUnknownTrigger(payload); } } if (isFullExecutionFromKnownTrigger(payload)) { if (triggerHasNoPinnedData(payload) && (await this.testWebhooks.needsWebhook({ userId: user.id, workflowEntity: payload.workflowData, additionalData: await WorkflowExecuteAdditionalData.getBase({ userId: user.id, workflowId: payload.workflowData.id, }), pushRef, triggerToStartFrom: payload.triggerToStartFrom, destinationNode: payload.destinationNode, workflowIsActive, }))) { return { waitingForWebhook: true }; } data = { executionMode: 'manual', pinData: payload.workflowData.pinData, pushRef, workflowData: payload.workflowData, userId: user.id, triggerToStartFrom: payload.triggerToStartFrom, agentRequest: payload.agentRequest, destinationNode: payload.destinationNode, }; } if (isFullExecutionFromUnknownTrigger(payload)) { const pinnedTrigger = this.selectPinnedTrigger(payload.workflowData, payload.destinationNode.nodeName, payload.workflowData.pinData ?? {}); if (pinnedTrigger === undefined && (await this.testWebhooks.needsWebhook({ userId: user.id, workflowEntity: payload.workflowData, additionalData: await WorkflowExecuteAdditionalData.getBase({ userId: user.id, workflowId: payload.workflowData.id, }), pushRef, destinationNode: payload.destinationNode, workflowIsActive, }))) { return { waitingForWebhook: true }; } data = { executionMode: 'manual', pinData: payload.workflowData.pinData, pushRef, workflowData: payload.workflowData, userId: user.id, agentRequest: payload.agentRequest, destinationNode: payload.destinationNode, triggerToStartFrom: pinnedTrigger ? { name: pinnedTrigger.name } : undefined, }; } if (data) { const offloadingManualExecutionsInQueueMode = this.globalConfig.executions.mode === 'queue' && process.env.OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS === 'true'; if (data.executionMode === 'manual' && offloadingManualExecutionsInQueueMode) { data.executionData = (0, n8n_workflow_1.createRunExecutionData)({ startData: { startNodes: data.startNodes, destinationNode: data.destinationNode, }, resultData: { pinData: data.pinData, runData: data.runData ?? null, }, manualData: { userId: data.userId, dirtyNodeNames: data.dirtyNodeNames, triggerToStartFrom: data.triggerToStartFrom, }, executionData: null, }); } const executionId = await this.workflowRunner.run(data); return { executionId }; } throw new n8n_workflow_1.UnexpectedError('`executeManually` was called with an unexpected payload', { extra: { payload }, }); } async executeChatWorkflow(workflowData, executionData, user, httpResponse, streamingEnabled, executionMode = 'chat') { const data = { executionMode, workflowData, userId: user.id, executionData, streamingEnabled, httpResponse, }; const executionId = await this.workflowRunner.run(data, undefined, true); return { executionId, }; } async executeErrorWorkflow(workflowId, workflowErrorData, runningProject) { try { const workflowData = await this.workflowRepository.get({ id: workflowId }, { relations: ['activeVersion'] }); if (workflowData === null) { this.logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}". Could not find workflow "${workflowId}"`, { workflowId }); return; } if (workflowData.activeVersion === null) { this.logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}". Workflow "${workflowId}" is not active and cannot be executed`, { workflowId }); return; } const executionMode = 'error'; const workflowInstance = new n8n_workflow_1.Workflow({ id: workflowId, name: workflowData.name, nodeTypes: this.nodeTypes, nodes: workflowData.activeVersion.nodes, connections: workflowData.activeVersion.connections, active: true, staticData: workflowData.staticData, settings: workflowData.settings, }); try { const failedNode = workflowErrorData.execution?.lastNodeExecuted ? workflowInstance.getNode(workflowErrorData.execution?.lastNodeExecuted) : undefined; await this.subworkflowPolicyChecker.check(workflowInstance, workflowErrorData.workflow.id, failedNode ?? undefined); } catch (error) { const initialNode = workflowInstance.getStartNode(); if (initialNode) { const errorWorkflowPermissionError = new n8n_workflow_1.SubworkflowOperationError(`Another workflow: (ID ${workflowErrorData.workflow.id}) tried to invoke this workflow to handle errors.`, "Unfortunately current permissions do not allow this. Please check that this workflow's settings allow it to be called by others"); const fakeExecution = this.executionDataService.generateFailedExecutionFromError('error', errorWorkflowPermissionError, initialNode); const fullExecutionData = { data: fakeExecution.data, mode: fakeExecution.mode, finished: false, stoppedAt: new Date(), workflowData, waitTill: null, status: fakeExecution.status, workflowId: workflowData.id, }; await this.executionRepository.createNewExecution(fullExecutionData); } this.logger.info('Error workflow execution blocked due to subworkflow settings', { erroredWorkflowId: workflowErrorData.workflow.id, errorWorkflowId: workflowId, }); return; } let node; let workflowStartNode; const { errorTriggerType } = this.globalConfig.nodes; for (const nodeName of Object.keys(workflowInstance.nodes)) { node = workflowInstance.nodes[nodeName]; if (node.type === errorTriggerType) { workflowStartNode = node; } } if (workflowStartNode === undefined) { this.logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}". Could not find "${errorTriggerType}" in workflow "${workflowId}"`); return; } const parentExecution = workflowErrorData.execution?.id && workflowErrorData.workflow?.id ? { executionId: workflowErrorData.execution.id, workflowId: workflowErrorData.workflow.id, executionContext: workflowErrorData.execution.executionContext, } : undefined; const nodeExecutionStack = []; nodeExecutionStack.push({ node: workflowStartNode, data: { main: [ [ { json: workflowErrorData, }, ], ], }, source: null, ...(parentExecution && { metadata: { parentExecution, }, }), }); const runExecutionData = (0, n8n_workflow_1.createRunExecutionData)({ executionData: { nodeExecutionStack, }, }); const runData = { executionMode, executionData: runExecutionData, workflowData, projectId: runningProject.id, }; await this.workflowRunner.run(runData); } catch (error) { this.errorReporter.error(error); this.logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}": "${error.message}"`, { workflowId: workflowErrorData.workflow.id }); } } selectPinnedTrigger(workflow, destinationNode, pinData) { const allPinnedTriggers = this.findAllPinnedTriggers(workflow, pinData); if (allPinnedTriggers.length === 0) return undefined; const destinationParents = new Set(new n8n_workflow_1.Workflow({ nodes: workflow.nodes, connections: workflow.connections, active: workflow.activeVersionId !== null, nodeTypes: this.nodeTypes, }).getParentNodes(destinationNode)); const trigger = allPinnedTriggers.find((a) => destinationParents.has(a.name)); return trigger; } findAllPinnedTriggers(workflow, pinData) { return workflow.nodes .filter((node) => !node.disabled && pinData?.[node.name] && ['trigger', 'webhook'].some((suffix) => node.type.toLowerCase().endsWith(suffix)) && node.type !== 'n8n-nodes-base.respondToWebhook') .sort((a) => (a.type.endsWith('webhook') ? -1 : 1)); } partialExecutionFulfilsPreconditions(payload) { if (this.isDestinationNodeATrigger(payload.destinationNode.nodeName, payload.workflowData)) { return false; } return (0, n8n_core_1.anyReachableRootHasRunData)(n8n_core_1.DirectedGraph.fromNodesAndConnections(payload.workflowData.nodes, payload.workflowData.connections), payload.destinationNode.nodeName, payload.runData); } }; exports.WorkflowExecutionService = WorkflowExecutionService; exports.WorkflowExecutionService = WorkflowExecutionService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, n8n_core_1.ErrorReporter, db_1.ExecutionRepository, db_1.WorkflowRepository, node_types_1.NodeTypes, test_webhooks_1.TestWebhooks, workflow_runner_1.WorkflowRunner, config_1.GlobalConfig, pre_execution_checks_1.SubworkflowPolicyChecker, execution_data_service_1.ExecutionDataService]) ], WorkflowExecutionService); function isPartialExecution(payload) { return 'destinationNode' in payload && 'runData' in payload; } function isFullExecutionFromKnownTrigger(payload) { return 'triggerToStartFrom' in payload; } function isFullExecutionFromUnknownTrigger(payload) { if ('triggerToStartFrom' in payload) { return false; } return !('runData' in payload); } function triggerHasNoPinnedData(payload) { return payload.workflowData.pinData?.[payload.triggerToStartFrom.name] === undefined; } function upgradeToFullManualExecutionFromUnknownTrigger(payload) { return { workflowData: payload.workflowData, destinationNode: payload.destinationNode, agentRequest: payload.agentRequest, }; } //# sourceMappingURL=workflow-execution.service.js.map