mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
refactor(core): Port workflow history config (#14689)
This commit is contained in:
12
packages/@n8n/config/src/configs/workflow-history.config.ts
Normal file
12
packages/@n8n/config/src/configs/workflow-history.config.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Config, Env } from '../decorators';
|
||||||
|
|
||||||
|
@Config
|
||||||
|
export class WorkflowHistoryConfig {
|
||||||
|
/** Whether to save workflow history versions. */
|
||||||
|
@Env('N8N_WORKFLOW_HISTORY_ENABLED')
|
||||||
|
enabled: boolean = true;
|
||||||
|
|
||||||
|
/** Time (in hours) to keep workflow history versions for. `-1` means forever. */
|
||||||
|
@Env('N8N_WORKFLOW_HISTORY_PRUNE_TIME')
|
||||||
|
pruneTime: number = -1;
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ import { TagsConfig } from './configs/tags.config';
|
|||||||
import { TemplatesConfig } from './configs/templates.config';
|
import { TemplatesConfig } from './configs/templates.config';
|
||||||
import { UserManagementConfig } from './configs/user-management.config';
|
import { UserManagementConfig } from './configs/user-management.config';
|
||||||
import { VersionNotificationsConfig } from './configs/version-notifications.config';
|
import { VersionNotificationsConfig } from './configs/version-notifications.config';
|
||||||
|
import { WorkflowHistoryConfig } from './configs/workflow-history.config';
|
||||||
import { WorkflowsConfig } from './configs/workflows.config';
|
import { WorkflowsConfig } from './configs/workflows.config';
|
||||||
import { Config, Env, Nested } from './decorators';
|
import { Config, Env, Nested } from './decorators';
|
||||||
|
|
||||||
@@ -149,4 +150,7 @@ export class GlobalConfig {
|
|||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
partialExecutions: PartialExecutionsConfig;
|
partialExecutions: PartialExecutionsConfig;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
workflowHistory: WorkflowHistoryConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,6 +315,10 @@ describe('GlobalConfig', () => {
|
|||||||
partialExecutions: {
|
partialExecutions: {
|
||||||
version: 2,
|
version: 2,
|
||||||
},
|
},
|
||||||
|
workflowHistory: {
|
||||||
|
enabled: true,
|
||||||
|
pruneTime: -1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should use all default values when no env variables are defined', () => {
|
it('should use all default values when no env variables are defined', () => {
|
||||||
|
|||||||
@@ -301,22 +301,6 @@ export const schema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
workflowHistory: {
|
|
||||||
enabled: {
|
|
||||||
doc: 'Whether to save workflow history versions',
|
|
||||||
format: Boolean,
|
|
||||||
default: true,
|
|
||||||
env: 'N8N_WORKFLOW_HISTORY_ENABLED',
|
|
||||||
},
|
|
||||||
|
|
||||||
pruneTime: {
|
|
||||||
doc: 'Time (in hours) to keep workflow history versions for',
|
|
||||||
format: Number,
|
|
||||||
default: -1,
|
|
||||||
env: 'N8N_WORKFLOW_HISTORY_PRUNE_TIME',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
proxy_hops: {
|
proxy_hops: {
|
||||||
format: Number,
|
format: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ export class FrontendService {
|
|||||||
debugInEditor: this.license.isDebugInEditorLicensed(),
|
debugInEditor: this.license.isDebugInEditorLicensed(),
|
||||||
binaryDataS3: isS3Available && isS3Selected && isS3Licensed,
|
binaryDataS3: isS3Available && isS3Selected && isS3Licensed,
|
||||||
workflowHistory:
|
workflowHistory:
|
||||||
this.license.isWorkflowHistoryLicensed() && config.getEnv('workflowHistory.enabled'),
|
this.license.isWorkflowHistoryLicensed() && this.globalConfig.workflowHistory.enabled,
|
||||||
workerView: this.license.isWorkerViewLicensed(),
|
workerView: this.license.isWorkerViewLicensed(),
|
||||||
advancedPermissions: this.license.isAdvancedPermissionsLicensed(),
|
advancedPermissions: this.license.isAdvancedPermissionsLicensed(),
|
||||||
apiKeyScopes: this.license.isApiKeyScopesEnabled(),
|
apiKeyScopes: this.license.isApiKeyScopesEnabled(),
|
||||||
@@ -344,7 +344,7 @@ export class FrontendService {
|
|||||||
this.settings.variables.limit = this.license.getVariablesLimit();
|
this.settings.variables.limit = this.license.getVariablesLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.license.isWorkflowHistoryLicensed() && config.getEnv('workflowHistory.enabled')) {
|
if (this.globalConfig.workflowHistory.enabled && this.license.isWorkflowHistoryLicensed()) {
|
||||||
Object.assign(this.settings.workflowHistory, {
|
Object.assign(this.settings.workflowHistory, {
|
||||||
pruneTime: getWorkflowHistoryPruneTime(),
|
pruneTime: getWorkflowHistoryPruneTime(),
|
||||||
licensePruneTime: getWorkflowHistoryLicensePruneTime(),
|
licensePruneTime: getWorkflowHistoryLicensePruneTime(),
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import config from '@/config';
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
import { Container } from '@n8n/di';
|
||||||
|
|
||||||
import { License } from '@/license';
|
import { License } from '@/license';
|
||||||
import { getWorkflowHistoryPruneTime } from '@/workflows/workflow-history.ee/workflow-history-helper.ee';
|
import { getWorkflowHistoryPruneTime } from '@/workflows/workflow-history.ee/workflow-history-helper.ee';
|
||||||
import { mockInstance } from '@test/mocking';
|
import { mockInstance } from '@test/mocking';
|
||||||
|
|
||||||
let licensePruneTime = -1;
|
let licensePruneTime = -1;
|
||||||
|
const globalConfig = Container.get(GlobalConfig);
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
mockInstance(License, {
|
mockInstance(License, {
|
||||||
@@ -15,39 +18,39 @@ beforeAll(async () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
licensePruneTime = -1;
|
licensePruneTime = -1;
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
globalConfig.workflowHistory.pruneTime = -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getWorkflowHistoryPruneTime', () => {
|
describe('getWorkflowHistoryPruneTime', () => {
|
||||||
test('should return -1 (infinite) if config and license are -1', () => {
|
test('should return -1 (infinite) if config and license are -1', () => {
|
||||||
licensePruneTime = -1;
|
licensePruneTime = -1;
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
globalConfig.workflowHistory.pruneTime = -1;
|
||||||
|
|
||||||
expect(getWorkflowHistoryPruneTime()).toBe(-1);
|
expect(getWorkflowHistoryPruneTime()).toBe(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return config time if license is infinite and config is not', () => {
|
test('should return config time if license is infinite and config is not', () => {
|
||||||
licensePruneTime = -1;
|
licensePruneTime = -1;
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
globalConfig.workflowHistory.pruneTime = 24;
|
||||||
|
|
||||||
expect(getWorkflowHistoryPruneTime()).toBe(24);
|
expect(getWorkflowHistoryPruneTime()).toBe(24);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return license time if config is infinite and license is not', () => {
|
test('should return license time if config is infinite and license is not', () => {
|
||||||
licensePruneTime = 25;
|
licensePruneTime = 25;
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
globalConfig.workflowHistory.pruneTime = -1;
|
||||||
|
|
||||||
expect(getWorkflowHistoryPruneTime()).toBe(25);
|
expect(getWorkflowHistoryPruneTime()).toBe(25);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return lowest of config and license time if both are not -1', () => {
|
test('should return lowest of config and license time if both are not -1', () => {
|
||||||
licensePruneTime = 26;
|
licensePruneTime = 26;
|
||||||
config.set('workflowHistory.pruneTime', 100);
|
globalConfig.workflowHistory.pruneTime = 100;
|
||||||
|
|
||||||
expect(getWorkflowHistoryPruneTime()).toBe(26);
|
expect(getWorkflowHistoryPruneTime()).toBe(26);
|
||||||
|
|
||||||
licensePruneTime = 100;
|
licensePruneTime = 100;
|
||||||
config.set('workflowHistory.pruneTime', 27);
|
globalConfig.workflowHistory.pruneTime = 27;
|
||||||
|
|
||||||
expect(getWorkflowHistoryPruneTime()).toBe(27);
|
expect(getWorkflowHistoryPruneTime()).toBe(27);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
import { Container } from '@n8n/di';
|
import { Container } from '@n8n/di';
|
||||||
|
|
||||||
import config from '@/config';
|
|
||||||
import { License } from '@/license';
|
import { License } from '@/license';
|
||||||
|
|
||||||
export function isWorkflowHistoryLicensed() {
|
export function isWorkflowHistoryLicensed() {
|
||||||
@@ -9,7 +9,7 @@ export function isWorkflowHistoryLicensed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isWorkflowHistoryEnabled() {
|
export function isWorkflowHistoryEnabled() {
|
||||||
return isWorkflowHistoryLicensed() && config.getEnv('workflowHistory.enabled');
|
return isWorkflowHistoryLicensed() && Container.get(GlobalConfig).workflowHistory.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkflowHistoryLicensePruneTime() {
|
export function getWorkflowHistoryLicensePruneTime() {
|
||||||
@@ -19,7 +19,7 @@ export function getWorkflowHistoryLicensePruneTime() {
|
|||||||
// Time in hours
|
// Time in hours
|
||||||
export function getWorkflowHistoryPruneTime(): number {
|
export function getWorkflowHistoryPruneTime(): number {
|
||||||
const licenseTime = Container.get(License).getWorkflowHistoryPruneLimit();
|
const licenseTime = Container.get(License).getWorkflowHistoryPruneLimit();
|
||||||
const configTime = config.getEnv('workflowHistory.pruneTime');
|
const configTime = Container.get(GlobalConfig).workflowHistory.pruneTime;
|
||||||
|
|
||||||
// License is infinite and config time is infinite
|
// License is infinite and config time is infinite
|
||||||
if (licenseTime === -1) {
|
if (licenseTime === -1) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
import { Container } from '@n8n/di';
|
import { Container } from '@n8n/di';
|
||||||
import { In } from '@n8n/typeorm';
|
import { In } from '@n8n/typeorm';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
|
||||||
import config from '@/config';
|
|
||||||
import { WorkflowHistoryRepository } from '@/databases/repositories/workflow-history.repository';
|
import { WorkflowHistoryRepository } from '@/databases/repositories/workflow-history.repository';
|
||||||
import { License } from '@/license';
|
import { License } from '@/license';
|
||||||
import { WorkflowHistoryManager } from '@/workflows/workflow-history.ee/workflow-history-manager.ee';
|
import { WorkflowHistoryManager } from '@/workflows/workflow-history.ee/workflow-history-manager.ee';
|
||||||
@@ -16,19 +16,21 @@ describe('Workflow History Manager', () => {
|
|||||||
const license = mockInstance(License);
|
const license = mockInstance(License);
|
||||||
let repo: WorkflowHistoryRepository;
|
let repo: WorkflowHistoryRepository;
|
||||||
let manager: WorkflowHistoryManager;
|
let manager: WorkflowHistoryManager;
|
||||||
|
let globalConfig: GlobalConfig;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await testDb.init();
|
await testDb.init();
|
||||||
repo = Container.get(WorkflowHistoryRepository);
|
repo = Container.get(WorkflowHistoryRepository);
|
||||||
manager = Container.get(WorkflowHistoryManager);
|
manager = Container.get(WorkflowHistoryManager);
|
||||||
|
globalConfig = Container.get(GlobalConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow']);
|
await testDb.truncate(['Workflow']);
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
||||||
config.set('workflowHistory.enabled', true);
|
globalConfig.workflowHistory.enabled = true;
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
globalConfig.workflowHistory.pruneTime = -1;
|
||||||
|
|
||||||
license.isWorkflowHistoryLicensed.mockReturnValue(true);
|
license.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||||
license.getWorkflowHistoryPruneLimit.mockReturnValue(-1);
|
license.getWorkflowHistoryPruneLimit.mockReturnValue(-1);
|
||||||
@@ -64,7 +66,7 @@ describe('Workflow History Manager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should not prune when licensed but disabled', async () => {
|
test('should not prune when licensed but disabled', async () => {
|
||||||
config.set('workflowHistory.enabled', false);
|
globalConfig.workflowHistory.enabled = false;
|
||||||
await createWorkflowHistory();
|
await createWorkflowHistory();
|
||||||
await pruneAndAssertCount();
|
await pruneAndAssertCount();
|
||||||
});
|
});
|
||||||
@@ -75,7 +77,7 @@ describe('Workflow History Manager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should prune when config prune time is not -1 (infinite)', async () => {
|
test('should prune when config prune time is not -1 (infinite)', async () => {
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
globalConfig.workflowHistory.pruneTime = 24;
|
||||||
await createWorkflowHistory();
|
await createWorkflowHistory();
|
||||||
await pruneAndAssertCount(0);
|
await pruneAndAssertCount(0);
|
||||||
});
|
});
|
||||||
@@ -88,7 +90,7 @@ describe('Workflow History Manager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should only prune versions older than prune time', async () => {
|
test('should only prune versions older than prune time', async () => {
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
globalConfig.workflowHistory.pruneTime = 24;
|
||||||
|
|
||||||
const recentVersions = await createWorkflowHistory(0);
|
const recentVersions = await createWorkflowHistory(0);
|
||||||
const oldVersions = await createWorkflowHistory();
|
const oldVersions = await createWorkflowHistory();
|
||||||
|
|||||||
Reference in New Issue
Block a user