refactor(core): Remove DB_SQLITE_ENABLE_WAL config (#24233)

This commit is contained in:
Artem Sorokin
2026-01-15 12:07:32 +01:00
committed by GitHub
parent 7c54ad36a2
commit 4df41dff6e
8 changed files with 10 additions and 211 deletions
@@ -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.
*
-1
View File
@@ -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 {
@@ -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;
}
}