mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 04:47:29 -08:00
feat(core): Run Error Workflow also on trigger activation error (#3470)
* feat(core): Run Error Workflow also when workflow gets deactivated
or could not be activated on startup because of error
R#
* ⚡ Add missing file
This commit is contained in:
parent
ff95de0bdd
commit
b5535e4a62
|
@ -13,6 +13,7 @@
|
||||||
import { ActiveWorkflows, NodeExecuteFunctions } from 'n8n-core';
|
import { ActiveWorkflows, NodeExecuteFunctions } from 'n8n-core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ExecutionError,
|
||||||
IDeferredPromise,
|
IDeferredPromise,
|
||||||
IExecuteData,
|
IExecuteData,
|
||||||
IExecuteResponsePromiseData,
|
IExecuteResponsePromiseData,
|
||||||
|
@ -22,11 +23,13 @@ import {
|
||||||
INodeExecutionData,
|
INodeExecutionData,
|
||||||
IRun,
|
IRun,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
|
IWorkflowBase,
|
||||||
IWorkflowExecuteAdditionalData as IWorkflowExecuteAdditionalDataWorkflow,
|
IWorkflowExecuteAdditionalData as IWorkflowExecuteAdditionalDataWorkflow,
|
||||||
NodeHelpers,
|
NodeHelpers,
|
||||||
WebhookHttpMethod,
|
WebhookHttpMethod,
|
||||||
Workflow,
|
Workflow,
|
||||||
WorkflowActivateMode,
|
WorkflowActivateMode,
|
||||||
|
WorkflowActivationError,
|
||||||
WorkflowExecuteMode,
|
WorkflowExecuteMode,
|
||||||
LoggerProxy as Logger,
|
LoggerProxy as Logger,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
@ -118,6 +121,7 @@ export class ActiveWorkflowRunner {
|
||||||
workflowName: workflowData.name,
|
workflowName: workflowData.name,
|
||||||
workflowId: workflowData.id,
|
workflowId: workflowData.id,
|
||||||
});
|
});
|
||||||
|
this.executeErrorWorkflow(error, workflowData, 'internal');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.verbose('Finished initializing active workflows (startup)');
|
Logger.verbose('Finished initializing active workflows (startup)');
|
||||||
|
@ -715,11 +719,39 @@ export class ActiveWorkflowRunner {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const activationError = new WorkflowActivationError(
|
||||||
|
'There was a problem with the trigger, for that reason did the workflow had to be deactivated',
|
||||||
|
error,
|
||||||
|
node,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.executeErrorWorkflow(activationError, workflowData, mode);
|
||||||
};
|
};
|
||||||
return returnFunctions;
|
return returnFunctions;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
executeErrorWorkflow(
|
||||||
|
error: ExecutionError,
|
||||||
|
workflowData: IWorkflowBase,
|
||||||
|
mode: WorkflowExecuteMode,
|
||||||
|
): void {
|
||||||
|
const fullRunData: IRun = {
|
||||||
|
data: {
|
||||||
|
resultData: {
|
||||||
|
error,
|
||||||
|
runData: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
finished: false,
|
||||||
|
mode,
|
||||||
|
startedAt: new Date(),
|
||||||
|
stoppedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
WorkflowExecuteAdditionalData.executeErrorWorkflow(workflowData, fullRunData, mode);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a workflow active
|
* Makes a workflow active
|
||||||
*
|
*
|
||||||
|
|
|
@ -27,7 +27,6 @@ import {
|
||||||
IRun,
|
IRun,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
ITaskData,
|
ITaskData,
|
||||||
IWorkflowCredentials,
|
|
||||||
IWorkflowExecuteAdditionalData,
|
IWorkflowExecuteAdditionalData,
|
||||||
IWorkflowExecuteHooks,
|
IWorkflowExecuteHooks,
|
||||||
IWorkflowHooksOptionalParameters,
|
IWorkflowHooksOptionalParameters,
|
||||||
|
@ -57,7 +56,6 @@ import {
|
||||||
Push,
|
Push,
|
||||||
ResponseHelper,
|
ResponseHelper,
|
||||||
WebhookHelpers,
|
WebhookHelpers,
|
||||||
WorkflowCredentials,
|
|
||||||
WorkflowHelpers,
|
WorkflowHelpers,
|
||||||
} from '.';
|
} from '.';
|
||||||
import {
|
import {
|
||||||
|
@ -66,7 +64,6 @@ import {
|
||||||
getWorkflowOwner,
|
getWorkflowOwner,
|
||||||
} from './UserManagement/UserManagementHelper';
|
} from './UserManagement/UserManagementHelper';
|
||||||
import { whereClause } from './WorkflowHelpers';
|
import { whereClause } from './WorkflowHelpers';
|
||||||
import { RESPONSE_ERROR_MESSAGES } from './constants';
|
|
||||||
|
|
||||||
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
|
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
|
||||||
|
|
||||||
|
@ -79,7 +76,7 @@ const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
|
||||||
* @param {WorkflowExecuteMode} mode The mode in which the workflow got started in
|
* @param {WorkflowExecuteMode} mode The mode in which the workflow got started in
|
||||||
* @param {string} [executionId] The id the execution got saved as
|
* @param {string} [executionId] The id the execution got saved as
|
||||||
*/
|
*/
|
||||||
function executeErrorWorkflow(
|
export function executeErrorWorkflow(
|
||||||
workflowData: IWorkflowBase,
|
workflowData: IWorkflowBase,
|
||||||
fullRunData: IRun,
|
fullRunData: IRun,
|
||||||
mode: WorkflowExecuteMode,
|
mode: WorkflowExecuteMode,
|
||||||
|
@ -1028,7 +1025,7 @@ export function sendMessageToUI(source: string, messages: any[]) {
|
||||||
* Returns the base additional data without webhooks
|
* Returns the base additional data without webhooks
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @param {IWorkflowCredentials} credentials
|
* @param {userId} string
|
||||||
* @param {INodeParameters} currentNodeParameters
|
* @param {INodeParameters} currentNodeParameters
|
||||||
* @returns {Promise<IWorkflowExecuteAdditionalData>}
|
* @returns {Promise<IWorkflowExecuteAdditionalData>}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
LoggerProxy as Logger,
|
LoggerProxy as Logger,
|
||||||
Workflow,
|
Workflow,
|
||||||
WorkflowActivateMode,
|
WorkflowActivateMode,
|
||||||
|
WorkflowActivationError,
|
||||||
WorkflowExecuteMode,
|
WorkflowExecuteMode,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
@ -82,17 +83,26 @@ export class ActiveWorkflows {
|
||||||
let triggerResponse: ITriggerResponse | undefined;
|
let triggerResponse: ITriggerResponse | undefined;
|
||||||
this.workflowData[id].triggerResponses = [];
|
this.workflowData[id].triggerResponses = [];
|
||||||
for (const triggerNode of triggerNodes) {
|
for (const triggerNode of triggerNodes) {
|
||||||
triggerResponse = await workflow.runTrigger(
|
try {
|
||||||
triggerNode,
|
triggerResponse = await workflow.runTrigger(
|
||||||
getTriggerFunctions,
|
triggerNode,
|
||||||
additionalData,
|
getTriggerFunctions,
|
||||||
mode,
|
additionalData,
|
||||||
activation,
|
mode,
|
||||||
);
|
activation,
|
||||||
if (triggerResponse !== undefined) {
|
);
|
||||||
// If a response was given save it
|
if (triggerResponse !== undefined) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// If a response was given save it
|
||||||
this.workflowData[id].triggerResponses!.push(triggerResponse);
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
this.workflowData[id].triggerResponses!.push(triggerResponse);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
|
throw new WorkflowActivationError(
|
||||||
|
'There was a problem activating the workflow',
|
||||||
|
error,
|
||||||
|
triggerNode,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,17 +110,26 @@ export class ActiveWorkflows {
|
||||||
if (pollNodes.length) {
|
if (pollNodes.length) {
|
||||||
this.workflowData[id].pollResponses = [];
|
this.workflowData[id].pollResponses = [];
|
||||||
for (const pollNode of pollNodes) {
|
for (const pollNode of pollNodes) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
try {
|
||||||
this.workflowData[id].pollResponses!.push(
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
await this.activatePolling(
|
this.workflowData[id].pollResponses!.push(
|
||||||
|
await this.activatePolling(
|
||||||
|
pollNode,
|
||||||
|
workflow,
|
||||||
|
additionalData,
|
||||||
|
getPollFunctions,
|
||||||
|
mode,
|
||||||
|
activation,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
|
throw new WorkflowActivationError(
|
||||||
|
'There was a problem activating the workflow',
|
||||||
|
error,
|
||||||
pollNode,
|
pollNode,
|
||||||
workflow,
|
);
|
||||||
additionalData,
|
}
|
||||||
getPollFunctions,
|
|
||||||
mode,
|
|
||||||
activation,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { URLSearchParams } from 'url';
|
||||||
import { IDeferredPromise } from './DeferredPromise';
|
import { IDeferredPromise } from './DeferredPromise';
|
||||||
import { Workflow } from './Workflow';
|
import { Workflow } from './Workflow';
|
||||||
import { WorkflowHooks } from './WorkflowHooks';
|
import { WorkflowHooks } from './WorkflowHooks';
|
||||||
|
import { WorkflowActivationError } from './WorkflowActivationError';
|
||||||
import { WorkflowOperationError } from './WorkflowErrors';
|
import { WorkflowOperationError } from './WorkflowErrors';
|
||||||
import { NodeApiError, NodeOperationError } from './NodeErrors';
|
import { NodeApiError, NodeOperationError } from './NodeErrors';
|
||||||
|
|
||||||
|
@ -56,7 +57,11 @@ export interface IConnection {
|
||||||
index: number;
|
index: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExecutionError = WorkflowOperationError | NodeOperationError | NodeApiError;
|
export type ExecutionError =
|
||||||
|
| WorkflowActivationError
|
||||||
|
| WorkflowOperationError
|
||||||
|
| NodeOperationError
|
||||||
|
| NodeApiError;
|
||||||
|
|
||||||
// Get used to gives nodes access to credentials
|
// Get used to gives nodes access to credentials
|
||||||
export interface IGetCredentials {
|
export interface IGetCredentials {
|
||||||
|
|
16
packages/workflow/src/WorkflowActivationError.ts
Normal file
16
packages/workflow/src/WorkflowActivationError.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// eslint-disable-next-line import/no-cycle
|
||||||
|
import { ExecutionBaseError, INode } from '.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for instantiating an workflow activation error
|
||||||
|
*/
|
||||||
|
export class WorkflowActivationError extends ExecutionBaseError {
|
||||||
|
node: INode | undefined;
|
||||||
|
|
||||||
|
constructor(message: string, error: Error, node?: INode) {
|
||||||
|
super(error);
|
||||||
|
this.node = node;
|
||||||
|
this.cause = error;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ export * from './NodeErrors';
|
||||||
export * as TelemetryHelpers from './TelemetryHelpers';
|
export * as TelemetryHelpers from './TelemetryHelpers';
|
||||||
export * from './RoutingNode';
|
export * from './RoutingNode';
|
||||||
export * from './Workflow';
|
export * from './Workflow';
|
||||||
|
export * from './WorkflowActivationError';
|
||||||
export * from './WorkflowDataProxy';
|
export * from './WorkflowDataProxy';
|
||||||
export * from './WorkflowErrors';
|
export * from './WorkflowErrors';
|
||||||
export * from './WorkflowHooks';
|
export * from './WorkflowHooks';
|
||||||
|
|
Loading…
Reference in a new issue