Fix multiple backups running at once
- Backups now have a cooldown, default of 30 seconds - Backups now have a lock, in the event of a TOC/TOU race condition, the lock will stop duplicate backups
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"enabled": true,
|
||||
"maxBackups": 15,
|
||||
"backupCooldown": 30,
|
||||
"directory": "./user/profiles/backups",
|
||||
"backupInterval": {
|
||||
"enabled": false,
|
||||
|
||||
@@ -13,6 +13,9 @@ public record BackupConfig : BaseConfig
|
||||
[JsonPropertyName("maxBackups")]
|
||||
public int MaxBackups { get; set; }
|
||||
|
||||
[JsonPropertyName("backupCooldown")]
|
||||
public int BackupCooldown { get; set; }
|
||||
|
||||
[JsonPropertyName("directory")]
|
||||
public string Directory { get; set; } = string.Empty;
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ public class BackupService
|
||||
// Runs Init() every x minutes
|
||||
protected Timer _backupIntervalTimer;
|
||||
|
||||
protected SemaphoreSlim BackupLock = new SemaphoreSlim(1, 1);
|
||||
protected long LastBackupTimestamp;
|
||||
|
||||
protected readonly FileUtil FileUtil;
|
||||
protected readonly JsonUtil JsonUtil;
|
||||
protected readonly ISptLogger<BackupService> Logger;
|
||||
@@ -78,7 +81,7 @@ public class BackupService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the backup process. <br />
|
||||
/// Run the backup process. <br />
|
||||
/// This method orchestrates the profile backup service. Handles copying profiles to a backup directory and cleaning
|
||||
/// up old backups if the number exceeds the configured maximum.
|
||||
/// </summary>
|
||||
@@ -89,6 +92,24 @@ public class BackupService
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we don't back up too often by using a configurable Cooldown
|
||||
var currentTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
if (currentTimestamp < LastBackupTimestamp + BackupConfig.BackupCooldown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LastBackupTimestamp = currentTimestamp;
|
||||
|
||||
// If the backup lock is already locked, skip backup. This is to stop TOC/TOU race conditions above
|
||||
// Passing 0 is a non-blocking Wait, will return false if the lock can't be acquired
|
||||
bool lockAcquired = await BackupLock.WaitAsync(0);
|
||||
if (!lockAcquired)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var targetDir = GenerateBackupTargetDir();
|
||||
|
||||
// Fetch all profiles in the profile directory.
|
||||
@@ -147,6 +168,11 @@ public class BackupService
|
||||
|
||||
CleanBackups();
|
||||
}
|
||||
finally
|
||||
{
|
||||
BackupLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if the backup service is enabled via the config.
|
||||
|
||||
Reference in New Issue
Block a user