fix(core): Force full execution data fetching for evaluation test runs (#27335)

This commit is contained in:
Arvin A 2026-03-23 10:56:05 +01:00 committed by GitHub
parent 3ad5926a5e
commit 87afcd8db4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 87 additions and 2 deletions

15
.vscode/launch.json vendored
View file

@ -32,6 +32,21 @@
"outputCapture": "std",
"killBehavior": "forceful"
},
{
"name": "Launch n8n CLI worker dev with debug",
"runtimeExecutable": "pnpm",
"cwd": "${workspaceFolder}/packages/cli",
"runtimeArgs": ["run", "dev:worker", "--", "--inspect-brk"],
"console": "integratedTerminal",
"restart": true,
"autoAttachChildProcesses": true,
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"envFile": "${workspaceFolder}/.env",
"outputCapture": "std",
"killBehavior": "polite"
},
{
"name": "Launch n8n CLI dev with debug",
"runtimeExecutable": "pnpm",

View file

@ -572,6 +572,57 @@ describe('workflow timeout with startedAt', () => {
});
});
describe('needsFullExecutionData', () => {
const originalEnv = process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING;
afterEach(() => {
if (originalEnv === undefined) {
delete process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING;
} else {
process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING = originalEnv;
}
});
it('should return true when forceFullExecutionData is true even with N8N_MINIMIZE_EXECUTION_DATA_FETCHING set', () => {
process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING = 'true';
// @ts-expect-error Private method
const result = runner.needsFullExecutionData('evaluation', 'exec-id', true);
expect(result).toBe(true);
});
it('should return true when env var is not set and forceFullExecutionData is undefined', () => {
delete process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING;
// @ts-expect-error Private method
const result = runner.needsFullExecutionData('webhook', 'exec-id', undefined);
expect(result).toBe(true);
});
it('should return false when env var is set, forceFullExecutionData is undefined, and mode is not integrated', () => {
process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING = 'true';
const activeExecutions = Container.get(ActiveExecutions);
jest.spyOn(activeExecutions, 'getResponseMode').mockReturnValue('responseNode');
// @ts-expect-error Private method
const result = runner.needsFullExecutionData('webhook', 'exec-id', undefined);
expect(result).toBe(false);
});
it('should return true when env var is set and mode is integrated', () => {
process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING = 'true';
// @ts-expect-error Private method
const result = runner.needsFullExecutionData('integrated', 'exec-id', undefined);
expect(result).toBe(true);
});
});
describe('streaming functionality', () => {
it('should setup sendChunk handler when streaming is enabled and execution mode is not manual', async () => {
// ARRANGE

View file

@ -489,6 +489,7 @@ describe('TestRunnerService', () => {
resource: 'dataset',
operation: 'getRows',
});
expect(runCallArg).toHaveProperty('forceFullExecutionData', true);
});
test('should call workflowRunner.run with correct data in queue execution mode and manual offload', async () => {
@ -575,6 +576,7 @@ describe('TestRunnerService', () => {
resource: 'dataset',
operation: 'getRows',
});
expect(runCallArg).toHaveProperty('forceFullExecutionData', true);
// after reset
delete process.env.OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS;
@ -742,6 +744,7 @@ describe('TestRunnerService', () => {
},
},
userId: metadata.userId,
forceFullExecutionData: true,
triggerToStartFrom: {
name: triggerNodeName,
},
@ -869,6 +872,7 @@ describe('TestRunnerService', () => {
expect(runCallArg).toEqual(
expect.objectContaining({
executionMode: 'evaluation',
forceFullExecutionData: true,
pinData: {
[triggerNodeName]: [testCase],
},

View file

@ -250,6 +250,7 @@ export class TestRunnerService {
const data: IWorkflowExecutionDataProcess = {
executionMode: 'evaluation',
pinData,
forceFullExecutionData: true,
workflowData: {
...workflow,
settings: {
@ -336,6 +337,7 @@ export class TestRunnerService {
destinationNode: { nodeName: triggerNode.name, mode: 'inclusive' },
executionMode: 'manual',
runData: {},
forceFullExecutionData: true,
workflowData: {
...workflow,
settings: {

View file

@ -489,7 +489,10 @@ export class WorkflowRunner {
let runData: IRun;
if (!jobResult || this.needsFullExecutionData(data.executionMode, executionId)) {
if (
!jobResult ||
this.needsFullExecutionData(data.executionMode, executionId, data.forceFullExecutionData)
) {
const fullExecutionData = await this.executionRepository.findSingleExecution(
executionId,
{
@ -561,7 +564,12 @@ export class WorkflowRunner {
* In all other cases we can skip the DB fetch and use the lightweight
* result summary sent by the worker via the job progress message.
*/
private needsFullExecutionData(executionMode: WorkflowExecuteMode, executionId: string): boolean {
private needsFullExecutionData(
executionMode: WorkflowExecuteMode,
executionId: string,
forceFullExecutionData?: boolean,
): boolean {
if (forceFullExecutionData) return true;
if (!process.env.N8N_MINIMIZE_EXECUTION_DATA_FETCHING) return true;
return (

View file

@ -2880,6 +2880,11 @@ export interface IWorkflowExecutionDataProcess {
destinationNode?: IDestinationNode;
restartExecutionId?: string;
executionMode: WorkflowExecuteMode;
/**
* When true, forces the execution data to be present in the run data
* ignores N8N_MINIMIZE_EXECUTION_DATA_FETCHING environment variable if set
*/
forceFullExecutionData?: boolean;
/**
* The data that is sent in the body of the webhook that started this
* execution.