Skip to content

Commit 36c25dd

Browse files
committed
fix: preserve locked snapshot visibility
(cherry picked from commit 3c3395b)
1 parent c378239 commit 36c25dd

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

lib/storage/account-snapshot.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ export async function statSnapshot(
1515
return { exists: true, bytes: stats.size, mtimeMs: stats.mtimeMs };
1616
} catch (error) {
1717
const code = (error as NodeJS.ErrnoException).code;
18+
if (code === "EBUSY" || code === "EPERM") {
19+
deps.logWarn("Backup candidate is locked", {
20+
path,
21+
error: String(error),
22+
});
23+
return { exists: true };
24+
}
1825
if (code !== "ENOENT") {
1926
deps.logWarn("Failed to stat backup candidate", {
2027
path,

test/account-snapshot.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ describe("statSnapshot", () => {
2828
expect.objectContaining({ path: "locked.json" }),
2929
);
3030
});
31+
it("treats locked snapshots as existing when stat returns EBUSY", async () => {
32+
const logWarn = vi.fn();
33+
await expect(
34+
statSnapshot("locked.json", {
35+
stat: vi.fn(async () => {
36+
throw Object.assign(new Error("busy"), { code: "EBUSY" });
37+
}),
38+
logWarn,
39+
}),
40+
).resolves.toEqual({ exists: true });
41+
expect(logWarn).toHaveBeenCalledWith(
42+
"Backup candidate is locked",
43+
expect.objectContaining({ path: "locked.json" }),
44+
);
45+
});
46+
3147
});
3248

3349
describe("describeAccountSnapshot", () => {

0 commit comments

Comments
 (0)