网站首页 网站源码
using Dpz.Core.Backup;
using Dpz.Core.EnumLibrary;
using Dpz.Core.Infrastructure;
using Dpz.Core.Infrastructure.Entity;
using Dpz.Core.Public.Entity;
using Dpz.Core.Public.ViewModel;
using Dpz.Core.Service.ObjectStorage.Services;
using Dpz.Core.Service.RepositoryService;
using Dpz.Core.Shard.Service;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
namespace Dpz.Core.Web.Jobs.Hangfire;
public class BackupActivator(
IBackupService backupService,
IBackupRecordService backupRecordService,
IConfiguration configuration,
ISafeFileService safeFileService,
ILogger<BackupActivator> logger
)
{
public async Task BackupAsync()
{
var filter = new Dictionary<string, string>
{
{
nameof(AccountToken),
SerializerFilterDocument(
new ExpressionFilterDefinition<AccountToken>(x =>
x.RefreshTokenExpiryTime > DateTime.Now
)
)
},
{
nameof(WaitExecution),
SerializerFilterDocument(
new ExpressionFilterDefinition<WaitExecution>(x =>
x.Status != ExecuteStatus.ExecuteComplete
)
)
},
};
try
{
await BackupMainAsync("mongodb", filter);
await BackupMainAsync("AgileConfig");
}
catch (Exception e)
{
logger.LogError(e, "backup fail");
}
}
private static string SerializerFilterDocument<T>(FilterDefinition<T> filter)
where T : IBaseEntity
{
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<T>();
var serializerArgs = new RenderArgs<T>(documentSerializer, serializerRegistry);
var result = filter.Render(serializerArgs);
return result.ToString();
}
private async Task BackupMainAsync(
string connectionStringName,
Dictionary<string, string>? filter = null
)
{
logger.LogInformation("Start backing up database: {Database}", connectionStringName);
var connectionString = configuration.GetConnectionString(connectionStringName);
backupService.UploadAsync = UploadAsync;
var backupRecord = await backupService.BackupAsync(connectionString, filter);
await backupRecordService.AddRecordAsync(backupRecord);
logger.LogInformation("Database: {Database} backup complete", connectionStringName);
}
private async Task<VmBackupRecord?> UploadAsync(BackupResult result)
{
if (string.IsNullOrEmpty(result.BackupPath))
{
throw new BusinessException("backup path is null");
}
if (!File.Exists(result.BackupPath))
{
throw new BusinessException("backup file not exist");
}
var fileName = Path.GetFileName(result.BackupPath);
var date = DateTime.Now;
List<string> pathToFile =
[
"backup",
date.Year.ToString(),
date.Month.ToString(),
$"{fileName}",
];
#if DEBUG
pathToFile.Insert(0, "Test");
#endif
var cloudFile = new CloudFile
{
PathToFile = pathToFile,
Stream = new FileStream(
result.BackupPath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
1 << 12
),
};
var address = await safeFileService.UploadFileForFtpAsync(cloudFile);
if (address == null)
{
throw new BusinessException("upload backup file fail");
}
return new VmBackupRecord
{
Filename = string.Join('/', pathToFile),
BackupTime = DateTime.Now,
Database = result.Database,
BackupPassword = result.ZipPassword,
};
}
}
这段代码是一个 C# 类 BackupActivator
的实现,主要用于执行数据库备份操作。它使用了 Hangfire 进行任务调度,并依赖于多个服务来完成备份的具体工作。以下是代码的主要功能和结构的详细解释:
备份数据库:
BackupAsync
方法是这个类的核心方法,负责执行数据库的备份操作。它会根据特定的过滤条件备份 MongoDB 数据库和 AgileConfig 数据库。过滤条件:
BackupAsync
方法中,定义了一个过滤条件字典 filter
,用于筛选需要备份的数据。这个过滤条件包括:AccountToken
:筛选 RefreshTokenExpiryTime
大于当前时间的记录。WaitExecution
:筛选状态不等于 ExecuteComplete
的记录。备份主逻辑:
BackupMainAsync
方法负责实际的备份操作。它接收数据库连接字符串的名称和可选的过滤条件,调用 backupService
的 BackupAsync
方法进行备份,并记录备份记录。序列化过滤器:
SerializerFilterDocument
方法用于将 MongoDB 的过滤器序列化为字符串,以便在备份时使用。上传备份文件:
UploadAsync
方法负责将备份文件上传到安全的文件存储服务(如 FTP)。它会检查备份路径是否有效,并在上传成功后返回备份记录。错误处理:
BackupAsync
方法中,使用 try-catch
块来捕获可能发生的异常,并记录错误信息。构造函数:
BackupActivator
的构造函数接受多个依赖项,包括备份服务、备份记录服务、配置、文件服务和日志记录器。这些依赖项通过依赖注入提供。异步方法:
async
和 await
关键字,以提高性能和响应性。条件编译:
#if DEBUG
指令在调试模式下修改备份文件的路径,以便于测试。整体而言,BackupActivator
类实现了一个完整的数据库备份解决方案,能够根据特定条件筛选数据,执行备份,并将备份文件上传到安全存储。它利用了现代 C# 的异步编程特性和依赖注入模式,使得代码结构清晰且易于维护。