feat: 文传易匿名临时文件传输站初始版本
- 后端 .NET 8 + FreeSql + 阿里云 OSS,支持共享/私密/标签三种文件模式 - 前端 Vue3 + Vite + TDesign,上传/取件/管理三页 - 取件码/二维码/海报合成(含保存二维码为图片) - deploy/ 部署文档与一键 FTP 发布脚本 - appsettings.json 含真实凭据,已 gitignore 不入库
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
using WenChuanyi.Api.Models;
|
||||
|
||||
namespace WenChuanyi.Api.Services;
|
||||
|
||||
/// <summary>过期文件定时清理:每 N 分钟扫描 IsPermanent=false 且已过期的记录,先删记录再删 OSS 对象</summary>
|
||||
public class ExpiredFileCleanerService : BackgroundService
|
||||
{
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger<ExpiredFileCleanerService> _logger;
|
||||
private readonly TimeSpan _interval;
|
||||
|
||||
public ExpiredFileCleanerService(
|
||||
IServiceScopeFactory scopeFactory,
|
||||
IConfiguration cfg,
|
||||
ILogger<ExpiredFileCleanerService> logger)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = logger;
|
||||
var minutes = cfg.GetValue<int>("Cleaner:IntervalMinutes", 30);
|
||||
_interval = TimeSpan.FromMinutes(Math.Max(1, minutes));
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("过期文件清理任务启动,间隔 {Minutes} 分钟", _interval.TotalMinutes);
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
await CleanExpiredAsync(stoppingToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "过期文件清理任务异常");
|
||||
}
|
||||
await Task.Delay(_interval, stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CleanExpiredAsync(CancellationToken ct)
|
||||
{
|
||||
await using var scope = _scopeFactory.CreateAsyncScope();
|
||||
var fsql = scope.ServiceProvider.GetRequiredService<IFreeSql>();
|
||||
var oss = scope.ServiceProvider.GetRequiredService<OssStorageService>();
|
||||
|
||||
var expired = await fsql.Select<FileItem>()
|
||||
.Where(f => !f.IsPermanent && f.ExpiresAt != null && f.ExpiresAt < DateTime.Now)
|
||||
.ToListAsync(ct);
|
||||
|
||||
if (expired.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("发现 {Count} 个过期文件,开始清理", expired.Count);
|
||||
foreach (var item in expired)
|
||||
{
|
||||
// 先删数据库记录
|
||||
var deleted = await fsql.Delete<FileItem>().Where(f => f.Id == item.Id).ExecuteAffrowsAsync(ct) > 0;
|
||||
// 再删 OSS 对象(失败仅记日志,不阻塞任务)
|
||||
if (deleted)
|
||||
{
|
||||
oss.TryDeleteObject(item.ObjectKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user