From c839d6cd490e355de1efa356327002b74d86ed75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Repe=C4=87?= Date: Thu, 15 Oct 2026 12:29:35 +0000 Subject: [PATCH] fix(core): Remove unused N8N_SCHEDULER_MIN_INTERVAL setting (#41194) --- .../__tests__/scheduler.config.test.ts | 11 ---------- .../config/src/configs/scheduler.config.ts | 18 ----------------- packages/@n8n/config/test/config.test.ts | 1 - .../__tests__/durable-scheduler.test.ts | 20 ++----------------- .../cli/src/scheduling/durable-scheduler.ts | 10 ++++------ 5 files changed, 6 insertions(+), 54 deletions(-) diff --git a/packages/@n8n/config/src/configs/__tests__/scheduler.config.test.ts b/packages/@n8n/config/src/configs/__tests__/scheduler.config.test.ts index 21ce64fb5b9..625b797db95 100644 --- a/packages/@n8n/config/src/configs/__tests__/scheduler.config.test.ts +++ b/packages/@n8n/config/src/configs/__tests__/scheduler.config.test.ts @@ -32,7 +32,6 @@ describe('SchedulerConfig', () => { expect(scheduler.retentionSeconds).toBe(24 * 60 * 60); expect(scheduler.failedRetentionSeconds).toBe(7 * 24 * 60 * 60); expect(scheduler.retentionIntervalSeconds).toBe(60 * 60); - expect(scheduler.minIntervalSeconds).toBe(0); expect(scheduler.jitterRatio).toBe(0.1); expect(scheduler.materializationTimeoutSeconds).toBe(60); expect(scheduler.executorTimeoutSeconds).toBe(60); @@ -74,7 +73,6 @@ describe('SchedulerConfig', () => { vi.stubEnv('N8N_SCHEDULER_RETENTION', '43200'); vi.stubEnv('N8N_SCHEDULER_FAILED_RETENTION', '86400'); vi.stubEnv('N8N_SCHEDULER_RETENTION_INTERVAL', '600'); - vi.stubEnv('N8N_SCHEDULER_MIN_INTERVAL', '15'); vi.stubEnv('N8N_SCHEDULER_JITTER_RATIO', '0.25'); vi.stubEnv('N8N_SCHEDULER_MATERIALIZATION_TIMEOUT', '30'); vi.stubEnv('N8N_SCHEDULER_EXECUTOR_TIMEOUT', '15'); @@ -97,7 +95,6 @@ describe('SchedulerConfig', () => { expect(scheduler.retentionSeconds).toBe(43200); expect(scheduler.failedRetentionSeconds).toBe(86400); expect(scheduler.retentionIntervalSeconds).toBe(600); - expect(scheduler.minIntervalSeconds).toBe(15); expect(scheduler.jitterRatio).toBe(0.25); expect(scheduler.materializationTimeoutSeconds).toBe(30); expect(scheduler.executorTimeoutSeconds).toBe(15); @@ -128,13 +125,5 @@ describe('SchedulerConfig', () => { expect(scheduler.taskTimeoutSeconds).toBe(300); }); - - it('should allow disabling the min-interval clamp with 0', () => { - vi.stubEnv('N8N_SCHEDULER_MIN_INTERVAL', '0'); - - const { scheduler } = Container.get(GlobalConfig); - - expect(scheduler.minIntervalSeconds).toBe(0); - }); }); }); diff --git a/packages/@n8n/config/src/configs/scheduler.config.ts b/packages/@n8n/config/src/configs/scheduler.config.ts index d84a09d1cc2..fcfdb4cfe1f 100644 --- a/packages/@n8n/config/src/configs/scheduler.config.ts +++ b/packages/@n8n/config/src/configs/scheduler.config.ts @@ -4,12 +4,6 @@ import { z } from 'zod'; import { Config, Env } from '../decorators'; import { positiveIntSchema } from '../schemas'; -/** - * Allows 0 (the clamp disabled) in addition to any positive value. Used for a - * setting where 0 is a meaningful "off", not just a smaller number. - */ -const nonNegativeIntSchema = z.number({ coerce: true }).int().nonnegative(); - /** * A jitter ratio: a fraction in [0, 1). 0 disables jitter; 1 or above would * allow a zero or negative delay between ticks, so they are rejected. @@ -233,18 +227,6 @@ export class SchedulerConfig { @Env('N8N_SCHEDULER_JITTER_RATIO', jitterRatioSchema) jitterRatio: number = 0.1; - /** - * The smallest gap, in seconds, allowed between consecutive runs of the same - * schedule. A schedule set to run more often than this is slowed down to this - * gap. Defaults to 0, which disables the limit and honours whatever interval - * each schedule specifies. - * - * Set it to put a floor on how frequently any schedule can run, for example to - * stop a misconfigured every-second schedule from overloading the instance. - */ - @Env('N8N_SCHEDULER_MIN_INTERVAL', nonNegativeIntSchema) - minIntervalSeconds: number = 0; - /** * How a Schedule Trigger node's "every N seconds/minutes" schedules run under * the durable scheduler. Defaults to `new`. diff --git a/packages/@n8n/config/test/config.test.ts b/packages/@n8n/config/test/config.test.ts index 4a36d555673..74cbbc3176d 100644 --- a/packages/@n8n/config/test/config.test.ts +++ b/packages/@n8n/config/test/config.test.ts @@ -513,7 +513,6 @@ describe('GlobalConfig', () => { retentionIntervalSeconds: 3600, retentionTimeoutSeconds: 300, jitterRatio: 0.1, - minIntervalSeconds: 0, maxConcurrentPasses: 10, triggerNodeMode: 'new', enabledForPollTriggers: false, diff --git a/packages/cli/src/scheduling/__tests__/durable-scheduler.test.ts b/packages/cli/src/scheduling/__tests__/durable-scheduler.test.ts index 82407af5351..0f9be59d613 100644 --- a/packages/cli/src/scheduling/__tests__/durable-scheduler.test.ts +++ b/packages/cli/src/scheduling/__tests__/durable-scheduler.test.ts @@ -32,7 +32,6 @@ describe('DurableScheduler', () => { instanceType = 'main', dbType = 'sqlite', materializationIntervalSeconds = 10, - minIntervalSeconds = 0, executorIntervalSeconds = 5, materializationWindowSeconds = 60, misfireGraceSeconds = 60, @@ -72,7 +71,6 @@ describe('DurableScheduler', () => { executorIntervalSeconds, jitterRatio: 0.1, materializationIntervalSeconds, - minIntervalSeconds, materializationWindowSeconds, misfireGraceSeconds, enabledForPollTriggers, @@ -137,8 +135,8 @@ describe('DurableScheduler', () => { describe('drain rate warning', () => { it('warns when a pass cannot drain the fastest possible schedule before the next one is due', () => { - // maxPerJob is 1000: a schedule as fast as this instance allows (the default - // floor of one second) can outrun a 1001s materialization interval. + // maxPerJob is 1000: a one-second schedule can outrun a 1001s materialization + // interval. const { logger } = makeScheduler({ materializationIntervalSeconds: 1001 }); expect(logger.warn).toHaveBeenCalledWith( @@ -155,20 +153,6 @@ describe('DurableScheduler', () => { expect.anything(), ); }); - - it('scales the threshold by an operator-configured minimum interval floor', () => { - // A 60s floor makes 1001s safe again: even the fastest schedule now - // produces at most one occurrence per 60s, well within maxPerJob's reach. - const { logger } = makeScheduler({ - materializationIntervalSeconds: 1001, - minIntervalSeconds: 60, - }); - - expect(logger.warn).not.toHaveBeenCalledWith( - expect.stringContaining('materialization interval'), - expect.anything(), - ); - }); }); describe('misfire grace warning', () => { diff --git a/packages/cli/src/scheduling/durable-scheduler.ts b/packages/cli/src/scheduling/durable-scheduler.ts index e37bf650852..f75d47820d3 100644 --- a/packages/cli/src/scheduling/durable-scheduler.ts +++ b/packages/cli/src/scheduling/durable-scheduler.ts @@ -179,15 +179,13 @@ function warnOnMisfireGrace(logger: Logger, config: GlobalConfig['scheduler']): * running. */ function warnOnDrainRate(logger: Logger, config: GlobalConfig['scheduler']): void { - const { materializationIntervalSeconds, minIntervalSeconds } = config; - // The fastest a schedule can legally fire: the operator's floor if they set - // one, otherwise the fastest an interval can be at all. - const fastestIntervalSeconds = minIntervalSeconds > 0 ? minIntervalSeconds : 1; - const drainSeconds = DEFAULT_MATERIALIZER_OPTIONS.maxPerJob * fastestIntervalSeconds; + const { materializationIntervalSeconds } = config; + // The fastest a schedule can fire is once per second. + const drainSeconds = DEFAULT_MATERIALIZER_OPTIONS.maxPerJob; if (materializationIntervalSeconds > drainSeconds) { logger.warn( 'Scheduler materialization interval is long enough that a pass may never fully drain the busiest possible schedule; under the coalesce misfire policy such a schedule could stop producing catch-up runs entirely', - { materializationIntervalSeconds, fastestIntervalSeconds }, + { materializationIntervalSeconds }, ); } }