Files
Automata/packages/cli/src/executionLifecycleHooks/restoreBinaryDataId.ts
Omar Ajoue 5ffff1bb22 fix: Stop binary data restoration from preventing execution from finishing (#8082)
In the case of a filesystem failure to rename the binary files as part
of the execution's cleanup process, the execution would fail to be saved
and would never finish. This catch prevents it.

## Summary
Whenever an execution is wrapping u to save the data, if it uses binary
data n8n will try to find possibly misallocated files and place them in
the right folder. If this process fails, the execution fails to finish.

Given the execution has already finished at this point, and we cannot
handle the binary data errors more gracefully, all we can do at this
point is log the message as it's a filesystem issue. The rest of the
execution saving process should remain as normal.



## Related tickets and issues
https://linear.app/n8n/issue/HELP-430



## Review / Merge checklist
- [ ] PR title and summary are descriptive. **Remember, the title
automatically goes into the changelog. Use `(no-changelog)` otherwise.**
([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md))
- [ ] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up
ticket created.
- [ ] Tests included.
> A bug is not considered fixed, unless a test is added to prevent it
from happening again.
   > A feature is not complete without tests.

---------

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
2023-12-21 09:40:39 +00:00

76 lines
2.4 KiB
TypeScript

import Container from 'typedi';
import { BinaryDataService } from 'n8n-core';
import type { IRun, WorkflowExecuteMode } from 'n8n-workflow';
import type { BinaryData } from 'n8n-core';
import config from '@/config';
import { Logger } from '@/Logger';
/**
* Whenever the execution ID is not available to the binary data service at the
* time of writing a binary data file, its name is missing the execution ID.
* This function restores the ID in the file name and run data reference.
*
* This edge case can happen only for a Webhook node that accepts binary data,
* when the binary data manager is set to persist this binary data.
*
* ```txt
* filesystem-v2:workflows/123/executions/temp/binary_data/69055-83c4-4493-876a-9092c4708b9b ->
* filesystem-v2:workflows/123/executions/390/binary_data/69055-83c4-4493-876a-9092c4708b9b
*
* s3:workflows/123/executions/temp/binary_data/69055-83c4-4493-876a-9092c4708b9b ->
* s3:workflows/123/executions/390/binary_data/69055-83c4-4493-876a-9092c4708b9b
* ```
*/
export async function restoreBinaryDataId(
run: IRun,
executionId: string,
workflowExecutionMode: WorkflowExecuteMode,
) {
if (
workflowExecutionMode !== 'webhook' ||
config.getEnv('binaryDataManager.mode') === 'default'
) {
return;
}
try {
const { runData } = run.data.resultData;
const promises = Object.keys(runData).map(async (nodeName) => {
const binaryDataId = runData[nodeName]?.[0]?.data?.main?.[0]?.[0]?.binary?.data?.id;
if (!binaryDataId) return;
const [mode, fileId] = binaryDataId.split(':') as [BinaryData.StoredMode, string];
const isMissingExecutionId = fileId.includes('/temp/');
if (!isMissingExecutionId) return;
const correctFileId = fileId.replace('temp', executionId);
await Container.get(BinaryDataService).rename(fileId, correctFileId);
const correctBinaryDataId = `${mode}:${correctFileId}`;
// @ts-expect-error Validated at the top
run.data.resultData.runData[nodeName][0].data.main[0][0].binary.data.id = correctBinaryDataId;
});
await Promise.all(promises);
} catch (e) {
const error = e instanceof Error ? e : new Error(`${e}`);
const logger = Container.get(Logger);
if (error.message.includes('ENOENT')) {
logger.warn('Failed to restore binary data ID - No such file or dir', {
executionId,
error,
});
return;
}
logger.error('Failed to restore binary data ID - Unknown error', { executionId, error });
}
}