From d065a1a910d30ff8c07abe78482a73823383f650 Mon Sep 17 00:00:00 2001 From: lluisemper <58423269+lluisemper@users.noreply.github.com> Date: Sat, 2 Aug 2025 20:28:23 +0200 Subject: [PATCH] src: add support for AbortSignal in backup method This adds support for passing an AbortSignal to the database backup function. If the signal is aborted during the backup process, the operation is interrupted and a rejection is returned with an AbortError. The signal is optionally passed through the options object. Internally, the signal is stored and periodically checked between backup steps to respond quickly to abort requests. This improves integration with modern web APIs and aligns with how abortable operations are handled elsewhere in the Node.js ecosystem. Fixes: https://github.com/nodejs/node/issues/58888 --- doc/api/sqlite.md | 35 +++++ lib/sqlite.js | 28 +++- src/env_properties.h | 2 + src/node_sqlite.cc | 165 ++++++++++++++++++++-- test/parallel/test-sqlite-backup-abort.js | 109 ++++++++++++++ 5 files changed, 328 insertions(+), 11 deletions(-) create mode 100644 test/parallel/test-sqlite-backup-abort.js diff --git a/doc/api/sqlite.md b/doc/api/sqlite.md index cf4871734bdad6..8c9c52a45645ee 100644 --- a/doc/api/sqlite.md +++ b/doc/api/sqlite.md @@ -763,8 +763,10 @@ changes: --> * `sourceDb` {DatabaseSync} The database to backup. The source database must be open. + * `path` {string | Buffer | URL} The path where the backup will be created. If the file already exists, the contents will be overwritten. + * `options` {Object} Optional configuration for the backup. The following properties are supported: * `source` {string} Name of the source database. This can be `'main'` (the default primary database) or any other @@ -774,6 +776,11 @@ changes: * `rate` {number} Number of pages to be transmitted in each batch of the backup. **Default:** `100`. * `progress` {Function} Callback function that will be called with the number of pages copied and the total number of pages. + * `signal` {AbortSignal} An optional AbortSignal that can be used to abort the backup operation.\ + If the signal is aborted, the backup operation will be cancelled and the Promise will reject with an `AbortError`.\ + **Note:** Aborting is a best-effort mechanism; the backup may complete before the abort is processed due to race + conditions. + * Returns: {Promise} A promise that resolves when the backup is completed and rejects if an error occurs. This method makes a database backup. This method abstracts the [`sqlite3_backup_init()`][], [`sqlite3_backup_step()`][] @@ -813,6 +820,34 @@ const totalPagesTransferred = await backup(sourceDb, 'backup.db', { console.log('Backup completed', totalPagesTransferred); ``` +### Aborting a backup + +The backup operation can be cancelled using an `AbortSignal`: + +```cjs +const { backup, DatabaseSync } = require('node:sqlite'); + +(async () => { + const sourceDb = new DatabaseSync('source.db'); + + try { + await backup(sourceDb, 'backup.db', { + signal: AbortSignal.timeout(5000), + progress: ({ totalPages, remainingPages }) => { + console.log('Backup in progress', { totalPages, remainingPages }); + }, + }); + console.log('Backup completed successfully'); + } catch (error) { + if (error.name === 'AbortError') { + console.log('Backup was cancelled:', error.message); + } else { + console.error('Backup failed:', error.message); + } + } +})(); +``` + ## `sqlite.constants`