fix(core): Recover successful data-less executions (#12720)

This commit is contained in:
Iván Ovejero 2025-01-22 09:00:17 +01:00 committed by GitHub
parent 97e651433b
commit a39b8bd32b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 4 deletions

View file

@ -3,6 +3,7 @@ import { stringify } from 'flatted';
import { mock } from 'jest-mock-extended'; import { mock } from 'jest-mock-extended';
import { InstanceSettings } from 'n8n-core'; import { InstanceSettings } from 'n8n-core';
import { randomInt } from 'n8n-workflow'; import { randomInt } from 'n8n-workflow';
import assert from 'node:assert';
import { ARTIFICIAL_TASK_DATA } from '@/constants'; import { ARTIFICIAL_TASK_DATA } from '@/constants';
import { ExecutionRepository } from '@/databases/repositories/execution.repository'; import { ExecutionRepository } from '@/databases/repositories/execution.repository';
@ -127,12 +128,15 @@ describe('ExecutionRecoveryService', () => {
}); });
describe('if leader, with 1+ messages', () => { describe('if leader, with 1+ messages', () => {
test('should return `null` if execution succeeded', async () => { test('for successful dataful execution, should return `null`', async () => {
/** /**
* Arrange * Arrange
*/ */
const workflow = await createWorkflow(); const workflow = await createWorkflow();
const execution = await createExecution({ status: 'success' }, workflow); const execution = await createExecution(
{ status: 'success', data: stringify({ runData: { foo: 'bar' } }) },
workflow,
);
const messages = setupMessages(execution.id, 'Some workflow'); const messages = setupMessages(execution.id, 'Some workflow');
/** /**
@ -170,7 +174,38 @@ describe('ExecutionRecoveryService', () => {
expect(amendedExecution).toBeNull(); expect(amendedExecution).toBeNull();
}); });
test('should update `status`, `stoppedAt` and `data` if last node did not finish', async () => { test('for successful dataless execution, should update `status`, `stoppedAt` and `data`', async () => {
/**
* Arrange
*/
const workflow = await createWorkflow();
const execution = await createExecution(
{
status: 'success',
data: stringify(undefined), // saved execution but likely crashed while saving high-volume data
},
workflow,
);
const messages = setupMessages(execution.id, 'Some workflow');
/**
* Act
*/
const amendedExecution = await executionRecoveryService.recoverFromLogs(
execution.id,
messages,
);
/**
* Assert
*/
assert(amendedExecution);
expect(amendedExecution.stoppedAt).not.toBe(execution.stoppedAt);
expect(amendedExecution.data).toEqual({ resultData: { runData: {} } });
expect(amendedExecution.status).toBe('crashed');
});
test('for running execution, should update `status`, `stoppedAt` and `data` if last node did not finish', async () => {
/** /**
* Arrange * Arrange
*/ */

View file

@ -73,7 +73,7 @@ export class ExecutionRecoveryService {
unflattenData: true, unflattenData: true,
}); });
if (!execution || execution.status === 'success') return null; if (!execution || (execution.status === 'success' && execution.data)) return null;
const runExecutionData = execution.data ?? { resultData: { runData: {} } }; const runExecutionData = execution.data ?? { resultData: { runData: {} } };