diff --git a/packages/@n8n/config/src/configs/executions.config.ts b/packages/@n8n/config/src/configs/executions.config.ts index 17dbe2c721..1f495e8580 100644 --- a/packages/@n8n/config/src/configs/executions.config.ts +++ b/packages/@n8n/config/src/configs/executions.config.ts @@ -70,4 +70,20 @@ export class ExecutionsConfig { @Nested queueRecovery: QueueRecoveryConfig; + + /** Whether to save execution data for failed production executions. This default can be overridden at a workflow level. */ + @Env('EXECUTIONS_DATA_SAVE_ON_ERROR') + saveDataOnError: 'all' | 'none' = 'all'; + + /** Whether to save execution data for successful production executions. This default can be overridden at a workflow level. */ + @Env('EXECUTIONS_DATA_SAVE_ON_SUCCESS') + saveDataOnSuccess: 'all' | 'none' = 'all'; + + /** Whether to save execution data as each node executes. This default can be overridden at a workflow level. */ + @Env('EXECUTIONS_DATA_SAVE_ON_PROGRESS') + saveExecutionProgress: boolean = false; + + /** Whether to save execution data for manual executions. This default can be overridden at a workflow level. */ + @Env('EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS') + saveDataManualExecutions: boolean = true; } diff --git a/packages/@n8n/config/test/config.test.ts b/packages/@n8n/config/test/config.test.ts index e5ceab5dd4..b140c69676 100644 --- a/packages/@n8n/config/test/config.test.ts +++ b/packages/@n8n/config/test/config.test.ts @@ -318,6 +318,10 @@ describe('GlobalConfig', () => { interval: 180, batchSize: 100, }, + saveDataOnError: 'all', + saveDataOnSuccess: 'all', + saveExecutionProgress: false, + saveDataManualExecutions: true, }, diagnostics: { enabled: true, diff --git a/packages/cli/src/config/schema.ts b/packages/cli/src/config/schema.ts index 9ab6ff09c8..0a0592f841 100644 --- a/packages/cli/src/config/schema.ts +++ b/packages/cli/src/config/schema.ts @@ -33,43 +33,6 @@ export const schema = { default: 3600, env: 'EXECUTIONS_TIMEOUT_MAX', }, - - // If a workflow executes all the data gets saved by default. This - // could be a problem when a workflow gets executed a lot and processes - // a lot of data. To not exceed the database's capacity it is possible to - // prune the database regularly or to not save the execution at all. - // Depending on if the execution did succeed or error a different - // save behaviour can be set. - saveDataOnError: { - doc: 'What workflow execution data to save on error', - format: ['all', 'none'] as const, - default: 'all', - env: 'EXECUTIONS_DATA_SAVE_ON_ERROR', - }, - saveDataOnSuccess: { - doc: 'What workflow execution data to save on success', - format: ['all', 'none'] as const, - default: 'all', - env: 'EXECUTIONS_DATA_SAVE_ON_SUCCESS', - }, - saveExecutionProgress: { - doc: 'Whether or not to save progress for each node executed', - format: Boolean, - default: false, - env: 'EXECUTIONS_DATA_SAVE_ON_PROGRESS', - }, - - // If the executions of workflows which got started via the editor - // should be saved. By default they will not be saved as this runs - // are normally only for testing and debugging. This setting can - // also be overwritten on a per workflow basis in the workflow settings - // in the editor. - saveDataManualExecutions: { - doc: 'Save data of executions when started manually via editor', - format: Boolean, - default: true, - env: 'EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS', - }, }, userManagement: { diff --git a/packages/cli/src/events/relays/telemetry.event-relay.ts b/packages/cli/src/events/relays/telemetry.event-relay.ts index 649b86e6aa..319abbc91e 100644 --- a/packages/cli/src/events/relays/telemetry.event-relay.ts +++ b/packages/cli/src/events/relays/telemetry.event-relay.ts @@ -831,12 +831,11 @@ export class TelemetryEventRelay extends EventRelay { executions_mode: config.getEnv('executions.mode'), executions_timeout: config.getEnv('executions.timeout'), executions_timeout_max: config.getEnv('executions.maxTimeout'), - executions_data_save_on_error: config.getEnv('executions.saveDataOnError'), - executions_data_save_on_success: config.getEnv('executions.saveDataOnSuccess'), - executions_data_save_on_progress: config.getEnv('executions.saveExecutionProgress'), - executions_data_save_manual_executions: config.getEnv( - 'executions.saveDataManualExecutions', - ), + executions_data_save_on_error: this.globalConfig.executions.saveDataOnError, + executions_data_save_on_success: this.globalConfig.executions.saveDataOnSuccess, + executions_data_save_on_progress: this.globalConfig.executions.saveExecutionProgress, + executions_data_save_manual_executions: + this.globalConfig.executions.saveDataManualExecutions, executions_data_prune: this.globalConfig.executions.pruneData, executions_data_max_age: this.globalConfig.executions.pruneDataMaxAge, }, diff --git a/packages/cli/src/execution-lifecycle/__tests__/to-save-settings.test.ts b/packages/cli/src/execution-lifecycle/__tests__/to-save-settings.test.ts index 8f1dea2e28..f09ff34a70 100644 --- a/packages/cli/src/execution-lifecycle/__tests__/to-save-settings.test.ts +++ b/packages/cli/src/execution-lifecycle/__tests__/to-save-settings.test.ts @@ -1,20 +1,26 @@ -import config from '@/config'; +import { GlobalConfig } from '@n8n/config'; +import { Container } from '@n8n/di'; import { toSaveSettings } from '../to-save-settings'; +const globalConfig = Container.get(GlobalConfig); + afterEach(() => { - config.load(config.default); + globalConfig.executions.saveDataOnError = 'all'; + globalConfig.executions.saveDataOnSuccess = 'all'; + globalConfig.executions.saveExecutionProgress = false; + globalConfig.executions.saveDataManualExecutions = true; }); describe('failed production executions', () => { it('should favor workflow settings over defaults', () => { - config.set('executions.saveDataOnError', 'none'); + globalConfig.executions.saveDataOnError = 'none'; const saveSettings = toSaveSettings({ saveDataErrorExecution: 'all' }); expect(saveSettings.error).toBe(true); - config.set('executions.saveDataOnError', 'all'); + globalConfig.executions.saveDataOnError = 'all'; const _saveSettings = toSaveSettings({ saveDataErrorExecution: 'none' }); @@ -22,13 +28,13 @@ describe('failed production executions', () => { }); it('should fall back to default if no workflow setting', () => { - config.set('executions.saveDataOnError', 'all'); + globalConfig.executions.saveDataOnError = 'all'; const saveSettings = toSaveSettings(); expect(saveSettings.error).toBe(true); - config.set('executions.saveDataOnError', 'none'); + globalConfig.executions.saveDataOnError = 'none'; const _saveSettings = toSaveSettings(); @@ -38,13 +44,13 @@ describe('failed production executions', () => { describe('successful production executions', () => { it('should favor workflow settings over defaults', () => { - config.set('executions.saveDataOnSuccess', 'none'); + globalConfig.executions.saveDataOnSuccess = 'none'; const saveSettings = toSaveSettings({ saveDataSuccessExecution: 'all' }); expect(saveSettings.success).toBe(true); - config.set('executions.saveDataOnSuccess', 'all'); + globalConfig.executions.saveDataOnSuccess = 'all'; const _saveSettings = toSaveSettings({ saveDataSuccessExecution: 'none' }); @@ -52,13 +58,13 @@ describe('successful production executions', () => { }); it('should fall back to default if no workflow setting', () => { - config.set('executions.saveDataOnSuccess', 'all'); + globalConfig.executions.saveDataOnSuccess = 'all'; const saveSettings = toSaveSettings(); expect(saveSettings.success).toBe(true); - config.set('executions.saveDataOnSuccess', 'none'); + globalConfig.executions.saveDataOnSuccess = 'none'; const _saveSettings = toSaveSettings(); @@ -68,13 +74,13 @@ describe('successful production executions', () => { describe('manual executions', () => { it('should favor workflow setting over default', () => { - config.set('executions.saveDataManualExecutions', false); + globalConfig.executions.saveDataManualExecutions = false; const saveSettings = toSaveSettings({ saveManualExecutions: true }); expect(saveSettings.manual).toBe(true); - config.set('executions.saveDataManualExecutions', true); + globalConfig.executions.saveDataManualExecutions = true; const _saveSettings = toSaveSettings({ saveManualExecutions: false }); @@ -82,13 +88,13 @@ describe('manual executions', () => { }); it('should favor fall back to default if workflow setting is explicit default', () => { - config.set('executions.saveDataManualExecutions', true); + globalConfig.executions.saveDataManualExecutions = true; const saveSettings = toSaveSettings({ saveManualExecutions: 'DEFAULT' }); expect(saveSettings.manual).toBe(true); - config.set('executions.saveDataManualExecutions', false); + globalConfig.executions.saveDataManualExecutions = false; const _saveSettings = toSaveSettings({ saveManualExecutions: 'DEFAULT' }); @@ -96,13 +102,13 @@ describe('manual executions', () => { }); it('should fall back to default if no workflow setting', () => { - config.set('executions.saveDataManualExecutions', true); + globalConfig.executions.saveDataManualExecutions = true; const saveSettings = toSaveSettings(); expect(saveSettings.manual).toBe(true); - config.set('executions.saveDataManualExecutions', false); + globalConfig.executions.saveDataManualExecutions = false; const _saveSettings = toSaveSettings(); @@ -112,13 +118,13 @@ describe('manual executions', () => { describe('execution progress', () => { it('should favor workflow setting over default', () => { - config.set('executions.saveExecutionProgress', false); + globalConfig.executions.saveExecutionProgress = false; const saveSettings = toSaveSettings({ saveExecutionProgress: true }); expect(saveSettings.progress).toBe(true); - config.set('executions.saveExecutionProgress', true); + globalConfig.executions.saveExecutionProgress = true; const _saveSettings = toSaveSettings({ saveExecutionProgress: false }); @@ -126,13 +132,13 @@ describe('execution progress', () => { }); it('should favor fall back to default if workflow setting is explicit default', () => { - config.set('executions.saveExecutionProgress', true); + globalConfig.executions.saveExecutionProgress = true; const saveSettings = toSaveSettings({ saveExecutionProgress: 'DEFAULT' }); expect(saveSettings.progress).toBe(true); - config.set('executions.saveExecutionProgress', false); + globalConfig.executions.saveExecutionProgress = false; const _saveSettings = toSaveSettings({ saveExecutionProgress: 'DEFAULT' }); @@ -140,13 +146,13 @@ describe('execution progress', () => { }); it('should fall back to default if no workflow setting', () => { - config.set('executions.saveExecutionProgress', true); + globalConfig.executions.saveExecutionProgress = true; const saveSettings = toSaveSettings(); expect(saveSettings.progress).toBe(true); - config.set('executions.saveExecutionProgress', false); + globalConfig.executions.saveExecutionProgress = false; const _saveSettings = toSaveSettings(); @@ -159,10 +165,10 @@ describe('null workflow settings', () => { expect(() => toSaveSettings(null)).not.toThrow(); // Should use defaults from config when settings are null - config.set('executions.saveDataOnError', 'all'); - config.set('executions.saveDataOnSuccess', 'all'); - config.set('executions.saveDataManualExecutions', true); - config.set('executions.saveExecutionProgress', true); + globalConfig.executions.saveDataOnError = 'all'; + globalConfig.executions.saveDataOnSuccess = 'all'; + globalConfig.executions.saveDataManualExecutions = true; + globalConfig.executions.saveExecutionProgress = true; const settingsWithNull = toSaveSettings(null); expect(settingsWithNull.error).toBe(true); diff --git a/packages/cli/src/execution-lifecycle/to-save-settings.ts b/packages/cli/src/execution-lifecycle/to-save-settings.ts index 8b017ab49d..819be07672 100644 --- a/packages/cli/src/execution-lifecycle/to-save-settings.ts +++ b/packages/cli/src/execution-lifecycle/to-save-settings.ts @@ -1,7 +1,7 @@ +import { GlobalConfig } from '@n8n/config'; +import { Container } from '@n8n/di'; import type { IWorkflowSettings } from 'n8n-workflow'; -import config from '@/config'; - export type ExecutionSaveSettings = { error: boolean | 'all' | 'none'; success: boolean | 'all' | 'none'; @@ -21,10 +21,10 @@ export function toSaveSettings( workflowSettings: IWorkflowSettings | null = {}, ): ExecutionSaveSettings { const DEFAULTS = { - ERROR: config.getEnv('executions.saveDataOnError'), - SUCCESS: config.getEnv('executions.saveDataOnSuccess'), - MANUAL: config.getEnv('executions.saveDataManualExecutions'), - PROGRESS: config.getEnv('executions.saveExecutionProgress'), + ERROR: Container.get(GlobalConfig).executions.saveDataOnError, + SUCCESS: Container.get(GlobalConfig).executions.saveDataOnSuccess, + MANUAL: Container.get(GlobalConfig).executions.saveDataManualExecutions, + PROGRESS: Container.get(GlobalConfig).executions.saveExecutionProgress, }; const { diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index 49da7d2036..1412d5a570 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -116,10 +116,10 @@ export class FrontendService { endpointWebhook: this.globalConfig.endpoints.webhook, endpointWebhookTest: this.globalConfig.endpoints.webhookTest, endpointWebhookWaiting: this.globalConfig.endpoints.webhookWaiting, - saveDataErrorExecution: config.getEnv('executions.saveDataOnError'), - saveDataSuccessExecution: config.getEnv('executions.saveDataOnSuccess'), - saveManualExecutions: config.getEnv('executions.saveDataManualExecutions'), - saveExecutionProgress: config.getEnv('executions.saveExecutionProgress'), + saveDataErrorExecution: this.globalConfig.executions.saveDataOnError, + saveDataSuccessExecution: this.globalConfig.executions.saveDataOnSuccess, + saveManualExecutions: this.globalConfig.executions.saveDataManualExecutions, + saveExecutionProgress: this.globalConfig.executions.saveExecutionProgress, executionTimeout: config.getEnv('executions.timeout'), maxExecutionTimeout: config.getEnv('executions.maxTimeout'), workflowCallerPolicyDefaultOption: this.globalConfig.workflows.callerPolicyDefaultOption,