使用LH-COS代替COS 💩 未经测试

This commit is contained in:
li-chx 2025-11-20 09:27:51 +08:00
parent f2001e2338
commit 5f3f3fd43e
7 changed files with 157 additions and 12 deletions

View File

@ -6,14 +6,101 @@ using System.Text;
namespace SQLBackupToCOS;
public class BackupService(ILogger<BackupService> logger, IConfiguration config, COSService cosService) : BackgroundService
public class BackupService(ILogger<BackupService> logger, IConfiguration config, OutputService outputService) : BackgroundService
{
private readonly ILogger<BackupService> _logger = logger;
private readonly IConfiguration _config = config;
private readonly COSService _cosService = cosService;
//private readonly COSService _cosService = cosService;
private readonly OutputService _outputService = outputService;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var startTime = _config.GetValue<string>("startedAt");
if (!string.IsNullOrWhiteSpace(startTime))
{
DateTime scheduledTime;
if (TimeOnly.TryParse(startTime, out var timeOnly))
{
// 只有时间(如 "08:00:00" 或 "08:00"
// 计算今天的目标时间UTC+8
TimeZoneInfo timeZone;
try
{
// 尝试使用跨平台的时区 ID
timeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Shanghai");
}
catch (TimeZoneNotFoundException)
{
// 回退到 Windows 时区 ID
timeZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
}
var nowUtc8 = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, timeZone);
// 构建今天的目标时间
scheduledTime = new DateTime(
nowUtc8.Year,
nowUtc8.Month,
nowUtc8.Day,
timeOnly.Hour,
timeOnly.Minute,
timeOnly.Second);
// 如果已经过了今天的时间,则安排到明天
if (scheduledTime <= nowUtc8)
{
scheduledTime = scheduledTime.AddDays(1);
_logger.LogInformation("Scheduled time already passed today, scheduling for tomorrow: {Time}", scheduledTime);
}
// 转换回 UTC 以便计算延迟
var scheduledTimeUtc = TimeZoneInfo.ConvertTimeToUtc(scheduledTime, timeZone);
var delay = scheduledTimeUtc - DateTime.UtcNow;
if (delay > TimeSpan.Zero)
{
_logger.LogInformation("Waiting until scheduled start time: {Time} UTC+8 (in {Delay})", scheduledTime, delay);
try
{
await Task.Delay(delay, stoppingToken);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Cancellation requested before start.");
return;
}
}
}
else if (DateTime.TryParse(startTime, out scheduledTime))
{
// 完整日期时间(如 "2024-01-15 08:00:00"
var delay = scheduledTime - DateTime.Now;
if (delay > TimeSpan.Zero)
{
_logger.LogInformation("Waiting until scheduled start time: {Time} (in {Delay})", scheduledTime, delay);
try
{
await Task.Delay(delay, stoppingToken);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Cancellation requested before start.");
return;
}
}
}
else
{
_logger.LogWarning("Invalid scheduled start time format: {Time}, starting immediately.", startTime);
}
}
else
{
_logger.LogInformation("No valid scheduled start time provided, starting immediately.");
}
var interval = TimeSpan.FromMinutes(_config.GetValue("BackupIntervalMinutes", 60));
using var timer = new PeriodicTimer(interval);
@ -98,7 +185,8 @@ public class BackupService(ILogger<BackupService> logger, IConfiguration config,
Directory.Delete(dumpDir, recursive: true);
_logger.LogInformation("Backup completed: {File}", finalDump);
await _cosService.AddFileToCOS(finalDump);
await _outputService.AddFileToOutput(finalDump);
//await _cosService.AddFileToCOS(finalDump);
}
catch (Exception ex)
{

View File

@ -7,16 +7,12 @@ using Microsoft.Extensions.Logging;
namespace SQLBackupToCOS
{
public class COSService
[Obsolete("This class uses COSXML SDK, now we migrated to use LH-COS")]
public class COSService(IConfiguration config, ILogger<COSService> logger)
{
private readonly IConfiguration _config;
private readonly ILogger _logger;
private readonly IConfiguration _config = config;
private readonly ILogger _logger = logger;
public COSService(IConfiguration config, ILogger<COSService> logger)
{
_config = config;
_logger = logger;
}
public async Task AddFileToCOS(string srcPath)
{
var bucketName = _config.GetValue<string>("COS:BucketName") ?? "my-bucket";

View File

@ -0,0 +1,52 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace SQLBackupToCOS
{
public class OutputService(IConfiguration config, ILogger<OutputService> logger)
{
private readonly IConfiguration _config = config;
private readonly ILogger _logger = logger;
public async Task AddFileToOutput(string srcPath)
{
try
{
string outputPath = _config.GetValue<string>("outputDir") ?? "/output";
Directory.CreateDirectory(outputPath);
// 构建目标文件完整路径
var fileName = Path.GetFileName(srcPath);
var destFilePath = Path.Combine(outputPath, fileName);
_logger.LogInformation("Copying backup file from {Source} to {Destination}", srcPath, destFilePath);
// 异步复制文件
await using var sourceStream = new FileStream(
srcPath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
81920,
FileOptions.Asynchronous);
await using var destStream = new FileStream(
destFilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None,
81920,
FileOptions.Asynchronous);
await sourceStream.CopyToAsync(destStream);
_logger.LogInformation("Backup file copied successfully to {Destination}", destFilePath);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to copy backup file to output directory");
throw;
}
}
}
}

View File

@ -7,7 +7,8 @@ var builder = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddLogging();
services.AddSingleton<COSService>();
//services.AddSingleton<COSService>();
services.AddSingleton<OutputService>();
services.AddHostedService<BackupService>();
});

View File

@ -6,6 +6,9 @@
}
},
"BackupIntervalMinutes": 60,
"extraDir": "",
"outputDir": "",
"startedAt": "",
"Database": {
"Host": "",
"User": "",

View File

@ -7,6 +7,8 @@
},
"BackupIntervalMinutes": 60,
"extraDir": "EXTRAPATH",
"outputDir": "OUTPUTPATH",
"startedAt": "STARTTIME",
"Database": {
"Host": "172.17.0.1",
"User": "SQLUSER",

View File

@ -14,7 +14,10 @@ services:
COS__SecretId: SECRETID
COS__SecretKey: SECRETKEY
COS__FilePath: PATH
startedAt: '03:00:00'
BackupIntervalMinutes: 1440
extraDir: EXTRAPATH
outputDir: OUTPUTPATH
volumes:
- srcDir:EXTRAPATH/srcDir:ro
- outputDir:OUTPUTPAPH:rw