From 0f7bcb3553fa895c8f12f573eafcf083e1816553 Mon Sep 17 00:00:00 2001 From: sneak Date: Wed, 14 Oct 2026 05:46:39 +0000 Subject: [PATCH] lib.backup() starts no further original once its lock is lost Issue 184 checked the backup's lock before each original, in the loop this branch replaces with several workers. Each worker now checks the lock before it takes the next file, so once the lock is lost no further original starts; the originals under way are finished, and the backup rejects once every worker has stopped. The README says the originals under way, not the one, are still stored. Model: opus-5-5 --- README.md | 6 +++--- TODO.md | 3 ++- src/backup.ts | 12 ++++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f8fb8a9..12fd670 100644 --- a/README.md +++ b/README.md @@ -779,9 +779,9 @@ A running backup loses its lock when someone removes `backup.lock`, or when another backup takes it over because the running one left it untouched for 10 seconds, as a stopped or stalled process does. The backup finds this out the next time it goes to touch the lock, which it does every 5 seconds, and then -stops before it starts another file. The original it is downloading at that -moment is still stored. It leaves `failures.json` and `backup.lock` as they are, -since another backup may be using them. `quak backup` prints +stops before it starts another file. The originals it is downloading at that +moment are still stored. It leaves `failures.json` and `backup.lock` as they +are, since another backup may be using them. `quak backup` prints `quak: lost the lock on : ` as one line and exits 1, and `lib.backup()` rejects with `lost the lock on : `. diff --git a/TODO.md b/TODO.md index 3c991de..999fd01 100644 --- a/TODO.md +++ b/TODO.md @@ -31,7 +31,8 @@ declares one. the work for one original, its `--verify` hashing included, so no more originals than that are open at once. `BackupLibrary` says the limit as `contentConcurrency`. A test holds each download at the fake Ente server to - count those in flight. + count those in flight. Each worker checks the backup's lock before it takes + the next file, so once the lock is lost no further original starts. - 2026-10-14: A backup whose lock is lost no longer dies with a stack trace (issue 184). `lockBackupDirectory` gives proper-lockfile an `onCompromised` diff --git a/src/backup.ts b/src/backup.ts index b3eb8d8..8a21adf 100644 --- a/src/backup.ts +++ b/src/backup.ts @@ -730,13 +730,17 @@ const runLockedBackup = async ( // Up to the content pool's limit of originals are worked on at once, // their `verify` hashing included, so however large the account is, no // more than that many are open. Each worker takes the next file from the - // iterator they all share until none is left. A worker that throws, as - // one does when `onProgress` throws, fails the backup only once every - // worker has stopped, so none writes into the backup after it has ended. + // iterator they all share until none is left, and throws instead once the + // lock is lost. A worker that throws, as one also does when `onProgress` + // throws, fails the backup only once every worker has stopped, so none + // writes into the backup after it has ended. if (includeOriginals) { const pending = distinct.values(); const worker = async (): Promise => { - for (const file of pending) await storeOriginal(file); + for (const file of pending) { + if (lock.lost) throw lock.lost; + await storeOriginal(file); + } }; const workers = await Promise.allSettled( Array.from({ length: lib.contentConcurrency }, worker),