diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index e24a6b586e..0743fe7421 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -43,6 +43,7 @@ import { } from 'n8n-workflow'; import pick from 'lodash.pick'; +import type { FindOptionsWhere } from 'typeorm'; import { LessThanOrEqual } from 'typeorm'; import { DateUtils } from 'typeorm/util/DateUtils'; import config from '@/config'; @@ -202,6 +203,7 @@ async function pruneExecutionData(this: WorkflowHooks): Promise { throttling = true; const timeout = config.getEnv('executions.pruneDataTimeout'); // in seconds const maxAge = config.getEnv('executions.pruneDataMaxAge'); // in h + const maxCount = config.getEnv('executions.pruneDataMaxCount'); const date = new Date(); // today date.setHours(date.getHours() - maxAge); @@ -209,7 +211,21 @@ async function pruneExecutionData(this: WorkflowHooks): Promise { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const utcDate = DateUtils.mixedDateToUtcDatetimeString(date); - const toPrune = { stoppedAt: LessThanOrEqual(utcDate) }; + const toPrune: FindOptionsWhere = { stoppedAt: LessThanOrEqual(utcDate) }; + + if (maxCount > 0) { + const executions = await Db.collections.Execution.find({ + select: ['id'], + skip: maxCount, + take: 1, + order: { id: 'DESC' }, + }); + + if (executions[0]) { + toPrune.id = LessThanOrEqual(executions[0].id); + } + } + const isBinaryModeDefaultMode = config.getEnv('binaryDataManager.mode') === 'default'; try { const executions = isBinaryModeDefaultMode diff --git a/packages/cli/src/config/schema.ts b/packages/cli/src/config/schema.ts index 9b91f411fb..1d660eb724 100644 --- a/packages/cli/src/config/schema.ts +++ b/packages/cli/src/config/schema.ts @@ -325,6 +325,16 @@ export const schema = { default: 3600, env: 'EXECUTIONS_DATA_PRUNE_TIMEOUT', }, + + // Additional pruning option to delete executions if total count exceeds the configured max. + // Deletes the oldest entries first + // Default is 0 = No limit + pruneDataMaxCount: { + doc: 'Maximum number of executions to keep in DB. Default 0 = no limit', + format: Number, + default: 0, + env: 'EXECUTIONS_DATA_PRUNE_MAX_COUNT', + }, }, queue: {