| | import { Logger } from '@n8n/backend-common'; |
| | import { GlobalConfig } from '@n8n/config'; |
| | import { Container } from '@n8n/di'; |
| | import { ErrorReporter } from 'n8n-core'; |
| | import type { IRun, IWorkflowBase, WorkflowExecuteMode } from 'n8n-workflow'; |
| |
|
| | import type { IWorkflowErrorData } from '@/interfaces'; |
| | import { OwnershipService } from '@/services/ownership.service'; |
| | import { UrlService } from '@/services/url.service'; |
| | |
| | import { WorkflowExecutionService } from '@/workflows/workflow-execution.service'; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | export function executeErrorWorkflow( |
| | workflowData: IWorkflowBase, |
| | fullRunData: IRun, |
| | mode: WorkflowExecuteMode, |
| | executionId?: string, |
| | retryOf?: string, |
| | ): void { |
| | const logger = Container.get(Logger); |
| |
|
| | |
| | let pastExecutionUrl: string | undefined; |
| | if (executionId !== undefined) { |
| | pastExecutionUrl = `${Container.get(UrlService).getWebhookBaseUrl()}workflow/${ |
| | workflowData.id |
| | }/executions/${executionId}`; |
| | } |
| |
|
| | if (fullRunData.data.resultData.error !== undefined) { |
| | let workflowErrorData: IWorkflowErrorData; |
| | const workflowId = workflowData.id; |
| |
|
| | if (executionId) { |
| | |
| | workflowErrorData = { |
| | execution: { |
| | id: executionId, |
| | url: pastExecutionUrl, |
| | error: fullRunData.data.resultData.error, |
| | lastNodeExecuted: fullRunData.data.resultData.lastNodeExecuted!, |
| | mode, |
| | retryOf, |
| | }, |
| | workflow: { |
| | id: workflowId, |
| | name: workflowData.name, |
| | }, |
| | }; |
| | } else { |
| | |
| | workflowErrorData = { |
| | trigger: { |
| | error: fullRunData.data.resultData.error, |
| | mode, |
| | }, |
| | workflow: { |
| | id: workflowId, |
| | name: workflowData.name, |
| | }, |
| | }; |
| | } |
| |
|
| | const { errorTriggerType } = Container.get(GlobalConfig).nodes; |
| | |
| | |
| | const { errorWorkflow } = workflowData.settings ?? {}; |
| | if (errorWorkflow && !(mode === 'error' && workflowId && errorWorkflow === workflowId)) { |
| | logger.debug('Start external error workflow', { |
| | executionId, |
| | errorWorkflowId: errorWorkflow, |
| | workflowId, |
| | }); |
| | |
| |
|
| | |
| | if (!workflowId) { |
| | |
| | |
| | |
| | return; |
| | } |
| |
|
| | Container.get(OwnershipService) |
| | .getWorkflowProjectCached(workflowId) |
| | .then((project) => { |
| | void Container.get(WorkflowExecutionService).executeErrorWorkflow( |
| | errorWorkflow, |
| | workflowErrorData, |
| | project, |
| | ); |
| | }) |
| | .catch((error: Error) => { |
| | Container.get(ErrorReporter).error(error); |
| | logger.error( |
| | `Could not execute ErrorWorkflow for execution ID ${executionId} because of error querying the workflow owner`, |
| | { |
| | executionId, |
| | errorWorkflowId: errorWorkflow, |
| | workflowId, |
| | error, |
| | workflowErrorData, |
| | }, |
| | ); |
| | }); |
| | } else if ( |
| | mode !== 'error' && |
| | workflowId !== undefined && |
| | workflowData.nodes.some((node) => node.type === errorTriggerType) |
| | ) { |
| | logger.debug('Start internal error workflow', { executionId, workflowId }); |
| | void Container.get(OwnershipService) |
| | .getWorkflowProjectCached(workflowId) |
| | .then((project) => { |
| | void Container.get(WorkflowExecutionService).executeErrorWorkflow( |
| | workflowId, |
| | workflowErrorData, |
| | project, |
| | ); |
| | }); |
| | } |
| | } |
| | } |
| |
|