refactor(core): Move error execution creation to execution service (no-changelog) (#8006)
Continue breaking down legacy helpers. Note: `getUserById` is unused.
This commit is contained in:
@@ -49,7 +49,7 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { ActiveExecutions } from '@/ActiveExecutions';
|
||||
import { createErrorExecution } from '@/GenericHelpers';
|
||||
import { ExecutionsService } from './executions/executions.service';
|
||||
import {
|
||||
STARTING_NODES,
|
||||
WORKFLOW_REACTIVATE_INITIAL_TIMEOUT,
|
||||
@@ -94,6 +94,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
||||
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private readonly multiMainSetup: MultiMainSetup,
|
||||
private readonly activationErrorsService: ActivationErrorsService,
|
||||
private readonly executionService: ExecutionsService,
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
@@ -547,9 +548,11 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
||||
};
|
||||
|
||||
returnFunctions.__emitError = (error: ExecutionError): void => {
|
||||
void createErrorExecution(error, node, workflowData, workflow, mode).then(() => {
|
||||
this.executeErrorWorkflow(error, workflowData, mode);
|
||||
});
|
||||
void this.executionService
|
||||
.createErrorExecution(error, node, workflowData, workflow, mode)
|
||||
.then(() => {
|
||||
this.executeErrorWorkflow(error, workflowData, mode);
|
||||
});
|
||||
};
|
||||
return returnFunctions;
|
||||
};
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import type express from 'express';
|
||||
import type {
|
||||
ExecutionError,
|
||||
INode,
|
||||
IRunExecutionData,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
} from 'n8n-workflow';
|
||||
import { validate } from 'class-validator';
|
||||
import { Container } from 'typedi';
|
||||
import config from '@/config';
|
||||
import type { ExecutionPayload, IWorkflowDb } from '@/Interfaces';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { UserUpdatePayload } from '@/requests';
|
||||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { BadRequestError } from './errors/response-errors/bad-request.error';
|
||||
|
||||
/**
|
||||
@@ -58,85 +48,4 @@ export async function validateEntity(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an error execution
|
||||
*
|
||||
* @param {INode} node
|
||||
* @param {IWorkflowDb} workflowData
|
||||
* @param {Workflow} workflow
|
||||
* @param {WorkflowExecuteMode} mode
|
||||
* @returns
|
||||
* @memberof ActiveWorkflowRunner
|
||||
*/
|
||||
|
||||
export async function createErrorExecution(
|
||||
error: ExecutionError,
|
||||
node: INode,
|
||||
workflowData: IWorkflowDb,
|
||||
workflow: Workflow,
|
||||
mode: WorkflowExecuteMode,
|
||||
): Promise<void> {
|
||||
const saveDataErrorExecutionDisabled = workflowData?.settings?.saveDataErrorExecution === 'none';
|
||||
|
||||
if (saveDataErrorExecutionDisabled) return;
|
||||
|
||||
const executionData: IRunExecutionData = {
|
||||
startData: {
|
||||
destinationNode: node.name,
|
||||
runNodeFilter: [node.name],
|
||||
},
|
||||
executionData: {
|
||||
contextData: {},
|
||||
metadata: {},
|
||||
nodeExecutionStack: [
|
||||
{
|
||||
node,
|
||||
data: {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
json: {},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
source: null,
|
||||
},
|
||||
],
|
||||
waitingExecution: {},
|
||||
waitingExecutionSource: {},
|
||||
},
|
||||
resultData: {
|
||||
runData: {
|
||||
[node.name]: [
|
||||
{
|
||||
startTime: 0,
|
||||
executionTime: 0,
|
||||
error,
|
||||
source: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
error,
|
||||
lastNodeExecuted: node.name,
|
||||
},
|
||||
};
|
||||
|
||||
const fullExecutionData: ExecutionPayload = {
|
||||
data: executionData,
|
||||
mode,
|
||||
finished: false,
|
||||
startedAt: new Date(),
|
||||
workflowData,
|
||||
workflowId: workflow.id,
|
||||
stoppedAt: new Date(),
|
||||
status: 'error',
|
||||
};
|
||||
|
||||
await Container.get(ExecutionRepository).createNewExecution(fullExecutionData);
|
||||
}
|
||||
|
||||
export const DEFAULT_EXECUTIONS_GET_ALL_LIMIT = 20;
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { User } from '@db/entities/User';
|
||||
import config from '@/config';
|
||||
import { License } from '@/License';
|
||||
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
|
||||
export function isSharingEnabled(): boolean {
|
||||
@@ -26,14 +25,6 @@ export function generateUserInviteUrl(inviterId: string, inviteeId: string): str
|
||||
return `${getInstanceBaseUrl()}/signup?inviterId=${inviterId}&inviteeId=${inviteeId}`;
|
||||
}
|
||||
|
||||
export async function getUserById(userId: string): Promise<User> {
|
||||
const user = await Container.get(UserRepository).findOneOrFail({
|
||||
where: { id: userId },
|
||||
relations: ['globalRole'],
|
||||
});
|
||||
return user;
|
||||
}
|
||||
|
||||
// return the difference between two arrays
|
||||
export function rightDiff<T1, T2>(
|
||||
[arr1, keyExtractor1]: [T1[], (item: T1) => string],
|
||||
|
||||
@@ -35,10 +35,7 @@ export type CredentialsGetSharedOptions =
|
||||
| { allowGlobalScope: false };
|
||||
|
||||
export class CredentialsService {
|
||||
static async get(
|
||||
where: FindOptionsWhere<ICredentialsDb>,
|
||||
options?: { relations: string[] },
|
||||
): Promise<ICredentialsDb | null> {
|
||||
static async get(where: FindOptionsWhere<ICredentialsDb>, options?: { relations: string[] }) {
|
||||
return Container.get(CredentialsRepository).findOne({
|
||||
relations: options?.relations,
|
||||
where,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { validate as jsonSchemaValidate } from 'jsonschema';
|
||||
import type { IWorkflowBase, JsonObject, ExecutionStatus } from 'n8n-workflow';
|
||||
import type {
|
||||
IWorkflowBase,
|
||||
JsonObject,
|
||||
ExecutionStatus,
|
||||
ExecutionError,
|
||||
INode,
|
||||
IRunExecutionData,
|
||||
WorkflowExecuteMode,
|
||||
} from 'n8n-workflow';
|
||||
import { ApplicationError, jsonParse, Workflow, WorkflowOperationError } from 'n8n-workflow';
|
||||
import type { FindOperator } from 'typeorm';
|
||||
import { In } from 'typeorm';
|
||||
@@ -7,9 +15,11 @@ import { ActiveExecutions } from '@/ActiveExecutions';
|
||||
import config from '@/config';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type {
|
||||
ExecutionPayload,
|
||||
IExecutionFlattedResponse,
|
||||
IExecutionResponse,
|
||||
IExecutionsListResponse,
|
||||
IWorkflowDb,
|
||||
IWorkflowExecutionDataProcess,
|
||||
} from '@/Interfaces';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
@@ -18,7 +28,7 @@ import type { ExecutionRequest } from '@/requests';
|
||||
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||
import * as GenericHelpers from '@/GenericHelpers';
|
||||
import { Container } from 'typedi';
|
||||
import { Container, Service } from 'typedi';
|
||||
import { getStatusUsingPreviousExecutionStatusMethod } from './executionHelpers';
|
||||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||
@@ -75,6 +85,7 @@ const schemaGetExecutionsQueryFilter = {
|
||||
|
||||
const allowedExecutionsQueryFilterFields = Object.keys(schemaGetExecutionsQueryFilter.properties);
|
||||
|
||||
@Service()
|
||||
export class ExecutionsService {
|
||||
/**
|
||||
* Function to get the workflow Ids for a User
|
||||
@@ -362,4 +373,75 @@ export class ExecutionsService {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async createErrorExecution(
|
||||
error: ExecutionError,
|
||||
node: INode,
|
||||
workflowData: IWorkflowDb,
|
||||
workflow: Workflow,
|
||||
mode: WorkflowExecuteMode,
|
||||
): Promise<void> {
|
||||
const saveDataErrorExecutionDisabled =
|
||||
workflowData?.settings?.saveDataErrorExecution === 'none';
|
||||
|
||||
if (saveDataErrorExecutionDisabled) return;
|
||||
|
||||
const executionData: IRunExecutionData = {
|
||||
startData: {
|
||||
destinationNode: node.name,
|
||||
runNodeFilter: [node.name],
|
||||
},
|
||||
executionData: {
|
||||
contextData: {},
|
||||
metadata: {},
|
||||
nodeExecutionStack: [
|
||||
{
|
||||
node,
|
||||
data: {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
json: {},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
source: null,
|
||||
},
|
||||
],
|
||||
waitingExecution: {},
|
||||
waitingExecutionSource: {},
|
||||
},
|
||||
resultData: {
|
||||
runData: {
|
||||
[node.name]: [
|
||||
{
|
||||
startTime: 0,
|
||||
executionTime: 0,
|
||||
error,
|
||||
source: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
error,
|
||||
lastNodeExecuted: node.name,
|
||||
},
|
||||
};
|
||||
|
||||
const fullExecutionData: ExecutionPayload = {
|
||||
data: executionData,
|
||||
mode,
|
||||
finished: false,
|
||||
startedAt: new Date(),
|
||||
workflowData,
|
||||
workflowId: workflow.id,
|
||||
stoppedAt: new Date(),
|
||||
status: 'error',
|
||||
};
|
||||
|
||||
await Container.get(ExecutionRepository).createNewExecution(fullExecutionData);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user