doc JobPack.cs
This commit is contained in:
@@ -1,18 +1,46 @@
|
|||||||
namespace Dlhis.ScheduledTask.Attributes;
|
namespace Dlhis.ScheduledTask.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于标记一个类为定时任务的特性。
|
||||||
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class RecurringJobAttribute : Attribute
|
public class RecurringJobAttribute : Attribute
|
||||||
{
|
{
|
||||||
public RecurringJobAttribute(string uniqueJobKey, string cron)
|
/// <summary>
|
||||||
|
/// 初始化 <see cref="RecurringJobAttribute"/> 类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uniqueJobKey">任务的唯一标识符。</param>
|
||||||
|
/// <param name="cron">Cron 表达式,定义任务的执行计划。</param>
|
||||||
|
/// <param name="runOnDevelopment">是否在开发环境中运行。</param>
|
||||||
|
public RecurringJobAttribute(string uniqueJobKey, string cron, bool runOnDevelopment = false)
|
||||||
{
|
{
|
||||||
UniqueJobKey = uniqueJobKey;
|
UniqueJobKey = uniqueJobKey;
|
||||||
Cron = cron;
|
Cron = cron;
|
||||||
|
RunOnDevelopment = runOnDevelopment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务名称(可选)。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务的唯一标识符。
|
||||||
|
/// </summary>
|
||||||
public string UniqueJobKey { get; }
|
public string UniqueJobKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cron 表达式,定义任务的执行计划。
|
||||||
|
/// </summary>
|
||||||
public string Cron { get; }
|
public string Cron { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否在开发环境中运行。
|
||||||
|
/// </summary>
|
||||||
|
public bool RunOnDevelopment { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务所属队列,默认为 "default"。
|
||||||
|
/// </summary>
|
||||||
public string Queue { get; set; } = "default";
|
public string Queue { get; set; } = "default";
|
||||||
}
|
}
|
||||||
@@ -8,40 +8,71 @@ using Kurisu.AspNetCore.Utils.Extensions;
|
|||||||
|
|
||||||
namespace Dlhis.ScheduledTask.Packs;
|
namespace Dlhis.ScheduledTask.Packs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示一个任务包,用于初始化并使用 Hangfire 调度定时任务。
|
||||||
|
/// </summary>
|
||||||
public class JobPack : BaseAppPack
|
public class JobPack : BaseAppPack
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取任务包的执行顺序。此值决定任务包的执行顺序。
|
||||||
|
/// </summary>
|
||||||
public override int Order => 999;
|
public override int Order => 999;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 调用任务包以发现并调度定时任务。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceProvider">用于解析依赖项的服务提供器。</param>
|
||||||
public override void Invoke(IServiceProvider serviceProvider)
|
public override void Invoke(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
|
// 获取日志记录器和主机环境服务
|
||||||
var logger = serviceProvider.GetService<ILogger<JobPack>>();
|
var logger = serviceProvider.GetService<ILogger<JobPack>>();
|
||||||
|
var env = serviceProvider.GetService<IHostEnvironment>();
|
||||||
|
|
||||||
var jobs = Assembly.GetEntryAssembly().GetTypes()
|
// 发现所有继承自 BaseJob 且具有 RecurringJobAttribute 的类型
|
||||||
|
var jobs = Assembly.GetEntryAssembly()!.GetTypes()
|
||||||
.Where(x => x.IsAssignableTo(typeof(BaseJob)) && x != typeof(BaseJob))
|
.Where(x => x.IsAssignableTo(typeof(BaseJob)) && x != typeof(BaseJob))
|
||||||
.Where(x => x.IsDefined(typeof(RecurringJobAttribute)))
|
.Where(x => x.IsDefined(typeof(RecurringJobAttribute)))
|
||||||
|
// 如果当前环境为开发环境,仅筛选出 RunOnDevelopment 为 true 的任务类型
|
||||||
|
.WhereIf(env.IsDevelopment(), x => x.GetCustomAttribute<RecurringJobAttribute>()!.RunOnDevelopment)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
// 如果未发现任何任务,则直接返回
|
||||||
|
if (jobs.IsEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用反射获取 Job.FromExpression 私有方法
|
||||||
var setJob = typeof(Job).GetMethod(nameof(Job.FromExpression), BindingFlags.NonPublic | BindingFlags.Static, new[] { typeof(LambdaExpression), typeof(Type), typeof(string) });
|
var setJob = typeof(Job).GetMethod(nameof(Job.FromExpression), BindingFlags.NonPublic | BindingFlags.Static, new[] { typeof(LambdaExpression), typeof(Type), typeof(string) });
|
||||||
var m = (Lazy<RecurringJobManager>)typeof(RecurringJob).GetField("Instance", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
|
// 获取 RecurringJobManager 的单例实例
|
||||||
|
var m = (Lazy<RecurringJobManager>)typeof(RecurringJob).GetField("Instance", BindingFlags.NonPublic | BindingFlags.Static)!.GetValue(null)!;
|
||||||
|
|
||||||
(jobs.Select(job => job.GetCustomAttribute<RecurringJobAttribute>().UniqueJobKey).Distinct().Count() != jobs.Count).ThrowIfTrue("任务key重复");
|
// 确保所有任务的唯一键不重复
|
||||||
|
(jobs.Select(job => job.GetCustomAttribute<RecurringJobAttribute>()!.UniqueJobKey).Distinct().Count() != jobs.Count).ThrowIfTrue("任务key重复");
|
||||||
|
|
||||||
|
// 记录发现的任务数量
|
||||||
logger.LogDebug("一共获取{count}个调度任务", jobs.Count);
|
logger.LogDebug("一共获取{count}个调度任务", jobs.Count);
|
||||||
|
|
||||||
|
// 遍历每个发现的任务并进行调度
|
||||||
foreach (var job in jobs)
|
foreach (var job in jobs)
|
||||||
{
|
{
|
||||||
|
// 获取任务的 RecurringJobAttribute
|
||||||
var recurringSetting = job.GetCustomAttribute<RecurringJobAttribute>()!;
|
var recurringSetting = job.GetCustomAttribute<RecurringJobAttribute>()!;
|
||||||
|
// 确保 Cron 表达式已定义
|
||||||
recurringSetting.Cron.IsEmpty().ThrowIfTrue(job.Name + "尚未定义Cron");
|
recurringSetting.Cron.IsEmpty().ThrowIfTrue(job.Name + "尚未定义Cron");
|
||||||
|
|
||||||
|
// 创建调用任务 TodoAsync 方法的表达式
|
||||||
var parameterExpression = Expression.Parameter(job);
|
var parameterExpression = Expression.Parameter(job);
|
||||||
var todo = job.GetMethod(nameof(BaseJob.TodoAsync));
|
var todo = job.GetMethod(nameof(BaseJob.TodoAsync))!;
|
||||||
var todoExp = Expression.Call(parameterExpression, todo);
|
var todoExp = Expression.Call(parameterExpression, todo);
|
||||||
|
|
||||||
var nJob = (Job)setJob.Invoke(null, new object[] { Expression.Lambda(todoExp), job, recurringSetting.Queue });
|
// 使用私有方法 Job.FromExpression 创建一个新的 Hangfire 任务
|
||||||
|
var nJob = (Job)setJob!.Invoke(null, new object[] { Expression.Lambda(todoExp), job, recurringSetting.Queue });
|
||||||
|
// 在 RecurringJobManager 中添加或更新定时任务
|
||||||
m.Value.AddOrUpdate(recurringSetting.UniqueJobKey, nJob, recurringSetting.Cron, new RecurringJobOptions
|
m.Value.AddOrUpdate(recurringSetting.UniqueJobKey, nJob, recurringSetting.Cron, new RecurringJobOptions
|
||||||
{
|
{
|
||||||
TimeZone = TimeZoneInfo.Local
|
TimeZone = TimeZoneInfo.Local
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user