Files
OneDriveBackupService/Worker.cs

90 lines
3.0 KiB
C#

using System.Diagnostics;
using Cronos;
using OneDriveBackupService.Models;
using OneDriveBackupService.OneDrive;
namespace OneDriveBackupService;
public class Worker(ILogger<Worker> logger, ConfigData config, OneDriveClient client) : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
if (Environment.GetCommandLineArgs().Contains("--run-once")) {
logger.LogInformation("Manual backup triggered");
await RunBackup(DateTime.Now, stoppingToken);
Environment.Exit(0);
return;
}
var expression = CronExpression.Parse(config.Schedule);
while (!stoppingToken.IsCancellationRequested) {
var utcNow = DateTime.UtcNow;
var cronTime = expression.GetNextOccurrence(utcNow);
var delay = cronTime.GetValueOrDefault(utcNow) - utcNow;
if (delay < TimeSpan.Zero)
delay = TimeSpan.Zero;
if (!cronTime.HasValue) {
logger.LogError("Cron expression failed, falling back to default delay");
delay = TimeSpan.FromHours(12);
}
var nextRun = DateTime.Now + delay;
logger.LogInformation("Next backup: {time}", nextRun.ToString("f"));
await Task.Delay(delay, stoppingToken);
await RunBackup(nextRun, stoppingToken);
}
}
private async Task RunBackup(DateTime optimalTime, CancellationToken stoppingToken) {
logger.LogInformation("Starting backup at {now}", DateTime.Now.ToString("f"));
var file = await CreateBackupArchive(optimalTime, stoppingToken);
if (string.IsNullOrEmpty(file)) {
logger.LogError("Backup archive creation failed");
return;
}
client.UploadFile(file);
var count = client.DeleteOldFiles();
logger.LogInformation("Deleted {count} old backups", count);
logger.LogInformation("Backup completed");
}
private async Task<string> CreateBackupArchive(DateTime optimalTime, CancellationToken stoppingToken) {
var timestamp = optimalTime.ToString("yyyyMMdd_HHmmss");
var output = $"/tmp/backup_{timestamp}.tar.gz";
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "tar",
ArgumentList = {
"-czf",
output,
"-C",
config.LocalRoot,
"-T",
Path.Combine(config.LocalRoot, config.IncludeFile)
},
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.Start();
await process.WaitForExitAsync(stoppingToken);
if (process.ExitCode != 0) {
var error = await process.StandardError.ReadToEndAsync(stoppingToken);
logger.LogError(error);
return string.Empty;
}
return output;
}
}