Files
better-genshin-impact/BetterGenshinImpact/Service/QuartzSchedulerService.cs
辉鸭蛋 769e08edfd fix: 修复DPI缩放获取和定时触发器同步问题
修复 DpiHelper 在未初始化窗口句柄时获取 DPI 缩放值的问题,现在能正确处理多显示器场景。重构 QuartzSchedulerService 的触发器同步逻辑,确保定时任务正确更新。在添加/编辑触发器时增加 Cron 表达式格式校验,避免无效表达式导致调度失败。同时修复 ScriptService 中任务启动时的线程调度问题。
2026-05-09 02:50:52 +08:00

97 lines
3.3 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.Model.Gear.Triggers;
using BetterGenshinImpact.Model.Gear.Triggers.QuartzJob;
using BetterGenshinImpact.ViewModel.Pages.Component;
using BetterGenshinImpact.Service.GearTask;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Quartz;
using Quartz.Impl.Matchers;
namespace BetterGenshinImpact.Service;
/// <summary>
/// Quartz.NET 调度器服务
/// </summary>
public class QuartzSchedulerService(ILogger<QuartzSchedulerService> logger,
ISchedulerFactory schedulerFactory,
GearTriggerStorageService triggerStorageService) : IHostedService
{
private readonly ILogger<QuartzSchedulerService> _logger = logger;
private const string GearGroupName = "gear";
public async Task StartAsync(CancellationToken cancellationToken)
{
var (timedTriggers, _) = await triggerStorageService.LoadTriggersAsync();
await SyncTimedTriggersAsync(timedTriggers, cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public async Task SyncTimedTriggersAsync(IEnumerable<GearTriggerViewModel> timedTriggers, CancellationToken cancellationToken = default)
{
var scheduler = await schedulerFactory.GetScheduler(cancellationToken);
var existingJobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(GearGroupName), cancellationToken);
if (existingJobKeys.Count > 0)
{
await scheduler.DeleteJobs(existingJobKeys.ToList(), cancellationToken);
}
var jobsDictionary = BuildJobsDictionary(timedTriggers);
if (jobsDictionary.Count > 0)
{
await scheduler.ScheduleJobs(jobsDictionary, replace: true, cancellationToken);
}
}
private static Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>> BuildJobsDictionary(IEnumerable<GearTriggerViewModel> timedTriggers)
{
var allData = timedTriggers
.Where(t => t.IsEnabled && !string.IsNullOrWhiteSpace(t.CronExpression))
.Select(t => t.ToTrigger())
.OfType<QuartzCronGearTrigger>()
.ToList();
var jobsDictionary = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
foreach (var data in allData)
{
if (string.IsNullOrEmpty(data.CronExpression) || !data.IsEnabled)
{
continue;
}
var jobDataMap = new JobDataMap
{
{ "TriggerName", data.Name },
{ "TriggerId", System.Guid.NewGuid().ToString() },
{ "ShouldInterruptOthers", false },
{ "TaskDefinitionName", data.TaskDefinitionName }
};
var job = JobBuilder.Create<QuartzGearTaskJob>()
.WithIdentity($"job:{data.Name}", GearGroupName)
.UsingJobData(jobDataMap)
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity($"trigger:{data.Name}", GearGroupName)
.WithCronSchedule(data.CronExpression)
.ForJob(job)
.Build();
jobsDictionary.Add(job, new HashSet<ITrigger> { trigger });
}
return jobsDictionary;
}
}