refactor(core): Deprecate running manual executions in main in scaling mode (#13493)

This commit is contained in:
Iván Ovejero
2025-02-26 20:37:11 +01:00
committed by GitHub
parent d3fe3dea32
commit 83d03d53eb
2 changed files with 93 additions and 3 deletions

View File

@@ -1,6 +1,8 @@
import { captor, mock } from 'jest-mock-extended';
import type { Logger } from 'n8n-core';
import config from '@/config';
import { DeprecationService } from '../deprecation.service';
describe('DeprecationService', () => {
@@ -108,4 +110,76 @@ describe('DeprecationService', () => {
toTest(envVar, value, mustWarn);
});
});
describe('OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS', () => {
const envVar = 'OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS';
beforeEach(() => {
process.env = { N8N_RUNNERS_ENABLED: 'true' };
jest.spyOn(config, 'getEnv').mockImplementation((key) => {
if (key === 'executions.mode') return 'queue';
return undefined;
});
});
describe('when executions.mode is queue', () => {
test('should warn when OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS is false', () => {
process.env[envVar] = 'false';
const service = new DeprecationService(logger);
service.warn();
expect(logger.warn).toHaveBeenCalledTimes(1);
const warningMessage = logger.warn.mock.calls[0][0];
expect(warningMessage).toContain(envVar);
});
test('should warn when OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS is empty', () => {
process.env[envVar] = '';
const service = new DeprecationService(logger);
service.warn();
expect(logger.warn).toHaveBeenCalledTimes(1);
const warningMessage = logger.warn.mock.calls[0][0];
expect(warningMessage).toContain(envVar);
});
test('should not warn when OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS is true', () => {
process.env[envVar] = 'true';
const service = new DeprecationService(logger);
service.warn();
expect(logger.warn).not.toHaveBeenCalled();
});
test('should warn when OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS is undefined', () => {
delete process.env[envVar];
const service = new DeprecationService(logger);
service.warn();
expect(logger.warn).toHaveBeenCalledTimes(1);
const warningMessage = logger.warn.mock.calls[0][0];
expect(warningMessage).toContain(envVar);
});
});
describe('when executions.mode is not queue', () => {
test('should not warn', () => {
jest.spyOn(config, 'getEnv').mockImplementation((key) => {
if (key === 'executions.mode') return 'regular';
return;
});
process.env[envVar] = 'false';
const service = new DeprecationService(logger);
service.warn();
expect(logger.warn).not.toHaveBeenCalled();
});
});
});
});

View File

@@ -1,6 +1,8 @@
import { Service } from '@n8n/di';
import { Logger } from 'n8n-core';
import config from '@/config';
type EnvVarName = string;
type Deprecation = {
@@ -15,6 +17,9 @@ type Deprecation = {
/** Whether to show a deprecation warning if the env var is missing. */
warnIfMissing?: boolean;
/** Whether a config value is required to trigger a deprecation warning. */
matchConfig?: boolean;
};
const SAFE_TO_REMOVE = 'Remove this environment variable; it is no longer needed.';
@@ -48,6 +53,14 @@ export class DeprecationService {
checkValue: (value?: string) => value?.toLowerCase() !== 'true' && value !== '1',
warnIfMissing: true,
},
{
envVar: 'OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS',
message:
'Running manual executions in the main instance in scaling mode is deprecated. Manual executions will be routed to workers in a future version. Please set `OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true` to offload manual executions to workers and avoid potential issues in the future. Consider increasing memory available to workers and reducing memory available to main.',
checkValue: (value?: string) => value?.toLowerCase() !== 'true' && value !== '1',
warnIfMissing: true,
matchConfig: config.getEnv('executions.mode') === 'queue',
},
{
envVar: 'N8N_PARTIAL_EXECUTION_VERSION_DEFAULT',
checkValue: (value: string) => value === '1',
@@ -68,10 +81,13 @@ export class DeprecationService {
warn() {
this.deprecations.forEach((d) => {
const envValue = process.env[d.envVar];
const matchConfig = d.matchConfig === true || d.matchConfig === undefined;
const warnIfMissing = d.warnIfMissing !== undefined && envValue === undefined;
const checkValue = d.checkValue ? d.checkValue(envValue) : envValue !== undefined;
this.state.set(d, {
mustWarn:
(d.warnIfMissing !== undefined && envValue === undefined) ||
(d.checkValue ? d.checkValue(envValue) : envValue !== undefined),
mustWarn: matchConfig && (warnIfMissing || checkValue),
});
});