From 5097c92494aaa91f9c5b74a96cbb1e11a31844f9 Mon Sep 17 00:00:00 2001
From: Zack Pollard <zackpollard@ymail.com>
Date: Mon, 11 Nov 2024 12:08:52 +0000
Subject: [PATCH] fix(server): attempt to delete failed backups immediately
 after failure (#13995)

---
 server/src/services/backup.service.spec.ts | 8 ++++++++
 server/src/services/backup.service.ts      | 3 +++
 2 files changed, 11 insertions(+)

diff --git a/server/src/services/backup.service.spec.ts b/server/src/services/backup.service.spec.ts
index 5f00596622..7ec2bb87c1 100644
--- a/server/src/services/backup.service.spec.ts
+++ b/server/src/services/backup.service.spec.ts
@@ -146,6 +146,7 @@ describe(BackupService.name, () => {
       storageMock.readdir.mockResolvedValue([]);
       processMock.spawn.mockReturnValue(mockSpawn(0, 'data', ''));
       storageMock.rename.mockResolvedValue();
+      storageMock.unlink.mockResolvedValue();
       systemMock.get.mockResolvedValue(systemConfigStub.backupEnabled);
       storageMock.createWriteStream.mockReturnValue(new PassThrough());
     });
@@ -188,5 +189,12 @@ describe(BackupService.name, () => {
       const result = await sut.handleBackupDatabase();
       expect(result).toBe(JobStatus.FAILED);
     });
+    it('should ignore unlink failing and still return failed job status', async () => {
+      processMock.spawn.mockReturnValueOnce(mockSpawn(1, '', 'error'));
+      storageMock.unlink.mockRejectedValue(new Error('error'));
+      const result = await sut.handleBackupDatabase();
+      expect(storageMock.unlink).toHaveBeenCalled();
+      expect(result).toBe(JobStatus.FAILED);
+    });
   });
 });
diff --git a/server/src/services/backup.service.ts b/server/src/services/backup.service.ts
index d08e0d397b..40753a2c76 100644
--- a/server/src/services/backup.service.ts
+++ b/server/src/services/backup.service.ts
@@ -163,6 +163,9 @@ export class BackupService extends BaseService {
       await this.storageRepository.rename(backupFilePath, backupFilePath.replace('.tmp', ''));
     } catch (error) {
       this.logger.error('Database Backup Failure', error);
+      await this.storageRepository
+        .unlink(backupFilePath)
+        .catch((error) => this.logger.error('Failed to delete failed backup file', error));
       return JobStatus.FAILED;
     }