mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
perf(core): Deduplicate task runner data request response (no-changelog) (#11583)
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
This commit is contained in:
@@ -1,28 +1,25 @@
|
||||
import { getAdditionalKeys } from 'n8n-core';
|
||||
import {
|
||||
WorkflowDataProxy,
|
||||
// type IWorkflowDataProxyAdditionalKeys,
|
||||
Workflow,
|
||||
} from 'n8n-workflow';
|
||||
import { WorkflowDataProxy, Workflow } from 'n8n-workflow';
|
||||
import type {
|
||||
CodeExecutionMode,
|
||||
INode,
|
||||
ITaskDataConnections,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
WorkflowParameters,
|
||||
IDataObject,
|
||||
IExecuteData,
|
||||
INodeExecutionData,
|
||||
INodeParameters,
|
||||
IRunExecutionData,
|
||||
WorkflowExecuteMode,
|
||||
WorkflowParameters,
|
||||
ITaskDataConnections,
|
||||
INode,
|
||||
IRunExecutionData,
|
||||
EnvProviderState,
|
||||
IExecuteData,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import * as a from 'node:assert';
|
||||
import { runInNewContext, type Context } from 'node:vm';
|
||||
|
||||
import type { TaskResultData } from '@/runner-types';
|
||||
import type { MainConfig } from '@/config/main-config';
|
||||
import type { DataRequestResponse, PartialAdditionalData, TaskResultData } from '@/runner-types';
|
||||
import { type Task, TaskRunner } from '@/task-runner';
|
||||
|
||||
import { BuiltInsParser } from './built-ins-parser/built-ins-parser';
|
||||
@@ -33,7 +30,7 @@ import { makeSerializable } from './errors/serializable-error';
|
||||
import type { RequireResolver } from './require-resolver';
|
||||
import { createRequireResolver } from './require-resolver';
|
||||
import { validateRunForAllItemsOutput, validateRunForEachItemOutput } from './result-validation';
|
||||
import type { MainConfig } from '../config/main-config';
|
||||
import { DataRequestResponseReconstruct } from '../data-request/data-request-response-reconstruct';
|
||||
|
||||
export interface JSExecSettings {
|
||||
code: string;
|
||||
@@ -45,34 +42,19 @@ export interface JSExecSettings {
|
||||
mode: WorkflowExecuteMode;
|
||||
}
|
||||
|
||||
export interface PartialAdditionalData {
|
||||
executionId?: string;
|
||||
restartExecutionId?: string;
|
||||
restApiUrl: string;
|
||||
instanceBaseUrl: string;
|
||||
formWaitingBaseUrl: string;
|
||||
webhookBaseUrl: string;
|
||||
webhookWaitingBaseUrl: string;
|
||||
webhookTestBaseUrl: string;
|
||||
currentNodeParameters?: INodeParameters;
|
||||
executionTimeoutTimestamp?: number;
|
||||
userId?: string;
|
||||
variables: IDataObject;
|
||||
}
|
||||
|
||||
export interface DataRequestResponse {
|
||||
export interface JsTaskData {
|
||||
workflow: Omit<WorkflowParameters, 'nodeTypes'>;
|
||||
inputData: ITaskDataConnections;
|
||||
connectionInputData: INodeExecutionData[];
|
||||
node: INode;
|
||||
|
||||
runExecutionData: IRunExecutionData;
|
||||
runIndex: number;
|
||||
itemIndex: number;
|
||||
activeNodeName: string;
|
||||
connectionInputData: INodeExecutionData[];
|
||||
siblingParameters: INodeParameters;
|
||||
mode: WorkflowExecuteMode;
|
||||
envProviderState?: EnvProviderState;
|
||||
envProviderState: EnvProviderState;
|
||||
executeData?: IExecuteData;
|
||||
defaultReturnRunIndex: number;
|
||||
selfData: IDataObject;
|
||||
@@ -89,6 +71,8 @@ export class JsTaskRunner extends TaskRunner {
|
||||
|
||||
private readonly builtInsParser = new BuiltInsParser();
|
||||
|
||||
private readonly taskDataReconstruct = new DataRequestResponseReconstruct();
|
||||
|
||||
constructor(config: MainConfig, name = 'JS Task Runner') {
|
||||
super({
|
||||
taskType: 'javascript',
|
||||
@@ -115,33 +99,14 @@ export class JsTaskRunner extends TaskRunner {
|
||||
? neededBuiltInsResult.result
|
||||
: BuiltInsParserState.newNeedsAllDataState();
|
||||
|
||||
const data = await this.requestData<DataRequestResponse>(
|
||||
const dataResponse = await this.requestData<DataRequestResponse>(
|
||||
task.taskId,
|
||||
neededBuiltIns.toDataRequestParams(),
|
||||
);
|
||||
|
||||
/**
|
||||
* We request node types only when we know a task needs all nodes, because
|
||||
* needing all nodes means that the task relies on paired item functionality,
|
||||
* which is the same requirement for needing node types.
|
||||
*/
|
||||
if (neededBuiltIns.needsAllNodes) {
|
||||
const uniqueNodeTypes = new Map(
|
||||
data.workflow.nodes.map((node) => [
|
||||
`${node.type}|${node.typeVersion}`,
|
||||
{ name: node.type, version: node.typeVersion },
|
||||
]),
|
||||
);
|
||||
const data = this.reconstructTaskData(dataResponse);
|
||||
|
||||
const unknownNodeTypes = this.nodeTypes.onlyUnknown([...uniqueNodeTypes.values()]);
|
||||
|
||||
const nodeTypes = await this.requestNodeTypes<INodeTypeDescription[]>(
|
||||
task.taskId,
|
||||
unknownNodeTypes,
|
||||
);
|
||||
|
||||
this.nodeTypes.addNodeTypeDescriptions(nodeTypes);
|
||||
}
|
||||
await this.requestNodeTypeIfNeeded(neededBuiltIns, data.workflow, task.taskId);
|
||||
|
||||
const workflowParams = data.workflow;
|
||||
const workflow = new Workflow({
|
||||
@@ -201,7 +166,7 @@ export class JsTaskRunner extends TaskRunner {
|
||||
private async runForAllItems(
|
||||
taskId: string,
|
||||
settings: JSExecSettings,
|
||||
data: DataRequestResponse,
|
||||
data: JsTaskData,
|
||||
workflow: Workflow,
|
||||
customConsole: CustomConsole,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
@@ -248,7 +213,7 @@ export class JsTaskRunner extends TaskRunner {
|
||||
private async runForEachItem(
|
||||
taskId: string,
|
||||
settings: JSExecSettings,
|
||||
data: DataRequestResponse,
|
||||
data: JsTaskData,
|
||||
workflow: Workflow,
|
||||
customConsole: CustomConsole,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
@@ -315,7 +280,7 @@ export class JsTaskRunner extends TaskRunner {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
private createDataProxy(data: DataRequestResponse, workflow: Workflow, itemIndex: number) {
|
||||
private createDataProxy(data: JsTaskData, workflow: Workflow, itemIndex: number) {
|
||||
return new WorkflowDataProxy(
|
||||
workflow,
|
||||
data.runExecutionData,
|
||||
@@ -359,4 +324,43 @@ export class JsTaskRunner extends TaskRunner {
|
||||
|
||||
return new ExecutionError({ message: JSON.stringify(error) });
|
||||
}
|
||||
|
||||
private reconstructTaskData(response: DataRequestResponse): JsTaskData {
|
||||
return {
|
||||
...response,
|
||||
connectionInputData: this.taskDataReconstruct.reconstructConnectionInputData(
|
||||
response.inputData,
|
||||
),
|
||||
executeData: this.taskDataReconstruct.reconstructExecuteData(response),
|
||||
};
|
||||
}
|
||||
|
||||
private async requestNodeTypeIfNeeded(
|
||||
neededBuiltIns: BuiltInsParserState,
|
||||
workflow: JsTaskData['workflow'],
|
||||
taskId: string,
|
||||
) {
|
||||
/**
|
||||
* We request node types only when we know a task needs all nodes, because
|
||||
* needing all nodes means that the task relies on paired item functionality,
|
||||
* which is the same requirement for needing node types.
|
||||
*/
|
||||
if (neededBuiltIns.needsAllNodes) {
|
||||
const uniqueNodeTypes = new Map(
|
||||
workflow.nodes.map((node) => [
|
||||
`${node.type}|${node.typeVersion}`,
|
||||
{ name: node.type, version: node.typeVersion },
|
||||
]),
|
||||
);
|
||||
|
||||
const unknownNodeTypes = this.nodeTypes.onlyUnknown([...uniqueNodeTypes.values()]);
|
||||
|
||||
const nodeTypes = await this.requestNodeTypes<INodeTypeDescription[]>(
|
||||
taskId,
|
||||
unknownNodeTypes,
|
||||
);
|
||||
|
||||
this.nodeTypes.addNodeTypeDescriptions(nodeTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user