mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-01 15:47:41 +08:00
refactor(core): Remove DB_SQLITE_ENABLE_WAL config (#24233)
This commit is contained in:
@@ -13,7 +13,6 @@ services:
|
||||
- N8N_DIAGNOSTICS_ENABLED=false
|
||||
- N8N_USER_FOLDER=/n8n
|
||||
- DB_SQLITE_POOL_SIZE=3
|
||||
- DB_SQLITE_ENABLE_WAL=true
|
||||
# Task Runner config
|
||||
- N8N_RUNNERS_MODE=external
|
||||
- N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
|
||||
|
||||
@@ -142,12 +142,6 @@ export class SqliteConfig {
|
||||
@Env('DB_SQLITE_POOL_SIZE', sqlitePoolSizeSchema)
|
||||
poolSize: number = 3;
|
||||
|
||||
/**
|
||||
* Enable SQLite WAL mode.
|
||||
*/
|
||||
@Env('DB_SQLITE_ENABLE_WAL')
|
||||
enableWAL: boolean = this.poolSize > 1;
|
||||
|
||||
/**
|
||||
* Run `VACUUM` on startup to rebuild the database, reducing file size and optimizing indexes.
|
||||
*
|
||||
|
||||
@@ -96,7 +96,6 @@ describe('GlobalConfig', () => {
|
||||
},
|
||||
sqlite: {
|
||||
database: 'database.sqlite',
|
||||
enableWAL: true,
|
||||
executeVacuumOnStartup: false,
|
||||
poolSize: 3,
|
||||
},
|
||||
|
||||
@@ -53,32 +53,17 @@ describe('DbConnectionOptions', () => {
|
||||
dbConfig.type = 'sqlite';
|
||||
dbConfig.sqlite = {
|
||||
database: 'test.sqlite',
|
||||
poolSize: 0,
|
||||
enableWAL: false,
|
||||
poolSize: 3,
|
||||
executeVacuumOnStartup: false,
|
||||
};
|
||||
});
|
||||
|
||||
it('should return SQLite connection options when type is sqlite', () => {
|
||||
const result = dbConnectionOptions.getOptions();
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'sqlite',
|
||||
enableWAL: false,
|
||||
...commonOptions,
|
||||
database: path.resolve(n8nFolder, 'test.sqlite'),
|
||||
migrations: sqliteMigrations,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return SQLite connection options with pooling when poolSize > 0', () => {
|
||||
dbConfig.sqlite.poolSize = 5;
|
||||
|
||||
it('should return SQLite pooled connection options when type is sqlite', () => {
|
||||
const result = dbConnectionOptions.getOptions();
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'sqlite-pooled',
|
||||
poolSize: 5,
|
||||
poolSize: 3,
|
||||
enableWAL: true,
|
||||
acquireTimeout: 60_000,
|
||||
destroyTimeout: 5_000,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Service } from '@n8n/di';
|
||||
import type { DataSourceOptions, LoggerOptions } from '@n8n/typeorm';
|
||||
import type { MysqlConnectionOptions } from '@n8n/typeorm/driver/mysql/MysqlConnectionOptions';
|
||||
import type { PostgresConnectionOptions } from '@n8n/typeorm/driver/postgres/PostgresConnectionOptions';
|
||||
import type { SqliteConnectionOptions } from '@n8n/typeorm/driver/sqlite/SqliteConnectionOptions';
|
||||
import type { SqlitePooledConnectionOptions } from '@n8n/typeorm/driver/sqlite-pooled/SqlitePooledConnectionOptions';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
import type { TlsOptions } from 'node:tls';
|
||||
@@ -75,32 +74,20 @@ export class DbConnectionOptions {
|
||||
};
|
||||
}
|
||||
|
||||
private getSqliteConnectionOptions(): SqliteConnectionOptions | SqlitePooledConnectionOptions {
|
||||
private getSqliteConnectionOptions(): SqlitePooledConnectionOptions {
|
||||
const { sqlite: sqliteConfig } = this.config;
|
||||
const { n8nFolder } = this.instanceSettingsConfig;
|
||||
|
||||
const commonOptions = {
|
||||
return {
|
||||
type: 'sqlite-pooled',
|
||||
poolSize: sqliteConfig.poolSize,
|
||||
enableWAL: true,
|
||||
acquireTimeout: 60_000,
|
||||
destroyTimeout: 5_000,
|
||||
...this.getCommonOptions(),
|
||||
database: path.resolve(n8nFolder, sqliteConfig.database),
|
||||
migrations: sqliteMigrations,
|
||||
};
|
||||
|
||||
if (sqliteConfig.poolSize > 0) {
|
||||
return {
|
||||
type: 'sqlite-pooled',
|
||||
poolSize: sqliteConfig.poolSize,
|
||||
enableWAL: true,
|
||||
acquireTimeout: 60_000,
|
||||
destroyTimeout: 5_000,
|
||||
...commonOptions,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'sqlite',
|
||||
enableWAL: sqliteConfig.enableWAL,
|
||||
...commonOptions,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getPostgresConnectionOptions(): PostgresConnectionOptions {
|
||||
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
|
||||
import { SqliteLegacyDriverRule } from '../sqlite-legacy-driver.rule';
|
||||
|
||||
describe('SqliteLegacyDriverRule', () => {
|
||||
let rule: SqliteLegacyDriverRule;
|
||||
let globalConfig: GlobalConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
globalConfig = mockInstance(GlobalConfig, {
|
||||
database: {
|
||||
type: 'postgresdb',
|
||||
sqlite: {
|
||||
poolSize: 0,
|
||||
enableWAL: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
rule = new SqliteLegacyDriverRule(globalConfig);
|
||||
});
|
||||
|
||||
describe('detect()', () => {
|
||||
it('should not be affected when using PostgreSQL', async () => {
|
||||
globalConfig.database.type = 'postgresdb';
|
||||
|
||||
const result = await rule.detect();
|
||||
|
||||
expect(result.isAffected).toBe(false);
|
||||
expect(result.instanceIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should not be affected when using SQLite with poolSize >= 1 and WAL enabled', async () => {
|
||||
globalConfig.database.type = 'sqlite';
|
||||
globalConfig.database.sqlite.poolSize = 3;
|
||||
globalConfig.database.sqlite.enableWAL = true;
|
||||
|
||||
const result = await rule.detect();
|
||||
|
||||
expect(result.isAffected).toBe(false);
|
||||
expect(result.instanceIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should be affected when using SQLite with poolSize < 1', async () => {
|
||||
globalConfig.database.type = 'sqlite';
|
||||
globalConfig.database.sqlite.poolSize = 0;
|
||||
|
||||
const result = await rule.detect();
|
||||
|
||||
expect(result.isAffected).toBe(true);
|
||||
expect(result.instanceIssues).toHaveLength(2);
|
||||
expect(result.instanceIssues[0].title).toBe('SQLite legacy driver removed');
|
||||
});
|
||||
|
||||
it('should be affected when using SQLite with WAL disabled', async () => {
|
||||
globalConfig.database.type = 'sqlite';
|
||||
globalConfig.database.sqlite.poolSize = 3;
|
||||
globalConfig.database.sqlite.enableWAL = false;
|
||||
|
||||
const result = await rule.detect();
|
||||
|
||||
expect(result.isAffected).toBe(true);
|
||||
expect(result.instanceIssues).toHaveLength(2);
|
||||
expect(result.instanceIssues[0].title).toBe('SQLite legacy driver removed');
|
||||
});
|
||||
|
||||
it('should be affected when using SQLite with both poolSize < 1 and WAL disabled', async () => {
|
||||
globalConfig.database.type = 'sqlite';
|
||||
globalConfig.database.sqlite.poolSize = 0;
|
||||
globalConfig.database.sqlite.enableWAL = false;
|
||||
|
||||
const result = await rule.detect();
|
||||
|
||||
expect(result.isAffected).toBe(true);
|
||||
expect(result.instanceIssues).toHaveLength(2);
|
||||
expect(result.instanceIssues[0].title).toBe('SQLite legacy driver removed');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,7 +11,6 @@ import { QueueWorkerMaxStalledCountRule } from './queue-worker-max-stalled-count
|
||||
import { RemovedDatabaseTypesRule } from './removed-database-types.rule';
|
||||
import { RemovedNodesRule } from './removed-nodes.rule';
|
||||
import { SettingsFilePermissionsRule } from './settings-file-permissions.rule';
|
||||
import { SqliteLegacyDriverRule } from './sqlite-legacy-driver.rule';
|
||||
import { TaskRunnerDockerImageRule } from './task-runner-docker-image.rule';
|
||||
import { TaskRunnersRule } from './task-runners.rule';
|
||||
import { TunnelOptionRule } from './tunnel-option.rule';
|
||||
@@ -40,7 +39,6 @@ const v2Rules = [
|
||||
SettingsFilePermissionsRule,
|
||||
TaskRunnersRule,
|
||||
TaskRunnerDockerImageRule,
|
||||
SqliteLegacyDriverRule,
|
||||
BinaryDataStorageRule,
|
||||
];
|
||||
export { v2Rules };
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { Service } from '@n8n/di';
|
||||
|
||||
import type {
|
||||
BreakingChangeRuleMetadata,
|
||||
IBreakingChangeInstanceRule,
|
||||
InstanceDetectionReport,
|
||||
} from '../../types';
|
||||
import { BreakingChangeCategory } from '../../types';
|
||||
|
||||
@Service()
|
||||
export class SqliteLegacyDriverRule implements IBreakingChangeInstanceRule {
|
||||
constructor(private readonly globalConfig: GlobalConfig) {}
|
||||
|
||||
id: string = 'sqlite-legacy-driver-v2';
|
||||
|
||||
getMetadata(): BreakingChangeRuleMetadata {
|
||||
return {
|
||||
version: 'v2',
|
||||
title: 'Remove SQLite legacy driver',
|
||||
description:
|
||||
'SQLite now uses WAL (Write-Ahead Logging) mode exclusively, with additional database files',
|
||||
category: BreakingChangeCategory.database,
|
||||
severity: 'low',
|
||||
documentationUrl: 'https://docs.n8n.io/2-0-breaking-changes/#remove-sqlite-legacy-driver',
|
||||
};
|
||||
}
|
||||
|
||||
async detect(): Promise<InstanceDetectionReport> {
|
||||
const result: InstanceDetectionReport = {
|
||||
isAffected: false,
|
||||
instanceIssues: [],
|
||||
recommendations: [],
|
||||
};
|
||||
|
||||
const dbType = this.globalConfig.database.type;
|
||||
// enableWAL is true if poolSize is > 1
|
||||
const enableWAL = this.globalConfig.database.sqlite.enableWAL;
|
||||
|
||||
// Only affected if using SQLite with WAL disabled
|
||||
if (dbType === 'sqlite' && !enableWAL) {
|
||||
result.isAffected = true;
|
||||
result.instanceIssues.push({
|
||||
title: 'SQLite legacy driver removed',
|
||||
description:
|
||||
'SQLite now uses WAL (Write-Ahead Logging) mode exclusively. The legacy driver (DB_SQLITE_POOL_SIZE=0) has been removed. Three database files will be created: database.sqlite (main), database.sqlite-wal (write-ahead log), and database.sqlite-shm (shared memory).',
|
||||
level: 'warning',
|
||||
});
|
||||
|
||||
result.instanceIssues.push({
|
||||
title: 'File system compatibility requirements',
|
||||
description:
|
||||
'Incompatible file systems include: NFS versions < 4, CIFS/SMB network shares, read-only file systems, and some container overlay filesystems.',
|
||||
level: 'warning',
|
||||
});
|
||||
|
||||
result.recommendations.push({
|
||||
action: 'Set DB_SQLITE_POOL_SIZE to enable WAL mode',
|
||||
description:
|
||||
'Set DB_SQLITE_POOL_SIZE to a value >= 1 (recommended: 3) to use the modern SQLite driver with WAL mode',
|
||||
});
|
||||
|
||||
result.recommendations.push({
|
||||
action: 'Update backup procedures',
|
||||
description:
|
||||
'Ensure backups include all three SQLite files (database.sqlite, database.sqlite-wal, database.sqlite-shm) or use the online backup API',
|
||||
});
|
||||
|
||||
result.recommendations.push({
|
||||
action: 'Verify file system compatibility',
|
||||
description:
|
||||
'Verify Docker volumes and file systems support shared memory operations required by WAL mode',
|
||||
});
|
||||
|
||||
result.recommendations.push({
|
||||
action: 'Rollback procedure if needed',
|
||||
description:
|
||||
'If rolling back to v1.x, convert back to rollback journal mode using: sqlite3 ~/.n8n/database.sqlite "PRAGMA journal_mode=DELETE;"',
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user