using FileShare_Services.Services.FileLibrary; using Microsoft.Extensions.Options; namespace FileShare_API.Services { /// /// 文件库定时扫描后台服务,按配置间隔检查是否有需要扫描的文件库目录。 /// public sealed class FileLibraryScanHostedService( IServiceScopeFactory scopeFactory, IOptions options, ILogger logger) : BackgroundService { /// 后台服务检查到期扫描任务的轮询间隔。 private readonly TimeSpan _interval = TimeSpan.FromMinutes(Math.Max(1, options.Value.PollingIntervalMinutes)); /// /// 启动扫描循环,首次立即执行,之后按配置的轮询间隔重复执行。 /// /// 应用关闭时触发的取消令牌。 protected override async Task ExecuteAsync(CancellationToken stoppingToken) { logger.LogInformation("文件库定时扫描服务已启动,轮询间隔 {IntervalMinutes} 分钟。", _interval.TotalMinutes); await ScanAsync(stoppingToken); using var timer = new PeriodicTimer(_interval); while (await timer.WaitForNextTickAsync(stoppingToken)) { await ScanAsync(stoppingToken); } } /// /// 创建临时作用域并调用 执行一次到期扫描。 /// /// 取消令牌。 private async Task ScanAsync(CancellationToken cancellationToken) { var startedAt = DateTime.UtcNow; logger.LogInformation("文件库定时扫描轮询开始。"); try { await using var scope = scopeFactory.CreateAsyncScope(); var scanner = scope.ServiceProvider.GetRequiredService(); await scanner.ScanDueRootsAsync(cancellationToken); logger.LogInformation( "文件库定时扫描轮询完成,耗时 {ElapsedMilliseconds} ms。", (DateTime.UtcNow - startedAt).TotalMilliseconds); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { logger.LogInformation("文件库定时扫描轮询已取消。"); } catch (Exception ex) { logger.LogWarning(ex, "文件库定时扫描失败。"); } } } }