.NET8 动态添加定时任务(CRON Expression, Whatever)

需要使用 Quartz .NET

csharp 复制代码
 <PackageReference Include="Quartz.AspNetCore"/>

建立 Global JobKey

csharp 复制代码
public static class GlobalJobKey
{
    public static JobKey CustomizedKey => new JobKey("xxx scheduled", "group1");
}

建立 Job

csharp 复制代码
public class CustomizedJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        // pass the parameter if you want,
        // depends on your business logic
        var customizedData =
            JsonSerializer.Deserialize<YourType>(context.MergedJobDataMap.Get("data").ToString()!);
      	// your logic
    }
}

在 Program.cs 中配置 Quartz .NET

csharp 复制代码
// construct the Quartz Trigger
builder.Services.AddQuartz(q =>
{
	q.AddJob<CustomizedJob>(opt => { opt.WithIdentity(GlobalJobKey.CustomizedKey).StoreDurably(); });
});

builder.Services.AddQuartzHostedService(options => { options.WaitForJobsToComplete = true; });

builder.Services.AddScoped<IJob, CustomizedJob>();

可以在任意地方: Controller, Background Service, Service... 中进行配置

csharp 复制代码
public class CustomizedBackgroundService(
    ISchedulerFactory factory,
    IServiceScopeFactory scopeFactory,
    ILogger<CustomizedBackgroundService> logger) : IHostedService
{
    private IScheduler? Schedule { get; set; }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        if (Schedule != null)
        {
            await StopJobs(cancellationToken);
        }

        using var scope = scopeFactory.CreateScope();
        var repo = scope.ServiceProvider.GetRequiredService<CustomizedRepository>();
        var configurations = (await repo.Query()).ToArray();
        Schedule = await factory.GetScheduler(cancellationToken);
        await Schedule.Start(cancellationToken);
        var jobDetail = JobBuilder.Create<CustomizedJob>()
            .WithIdentity(GlobalJobKey.CustomizedKey)
            .StoreDurably()
            .Build();

        await Schedule.AddJob(jobDetail, true, cancellationToken);

        Array.ForEach(configurations, Action);

        return;

        async void Action(CustomizedConfiguration configuration)
        {

            var triggerKey = new TriggerKey($"{configuration.Name}-trigger", "group1");

            var existingTrigger = await Schedule.GetTrigger(triggerKey, cancellationToken);
            if (existingTrigger != null)
                await Schedule.UnscheduleJob(triggerKey, cancellationToken);
            var trigger = TriggerBuilder.Create()
                .WithIdentity(triggerKey)
                .ForJob(GlobalJobKey.CustomizedKey)
         		.WithCronSchedule("0 0 0 ? * 1")
                .UsingJobData("data", JsonSerializer.Serialize(configuration))
                .StartNow()
                .Build();

            await Schedule.ScheduleJob(trigger, cancellationToken);

            logger.LogCritical("add trigger for: {Trigger}", $"{configuration.Name}-trigger");
        }
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        if (Schedule != null)
        {
            await StopJobs(cancellationToken);
        }
    }

    private async Task StopJobs(CancellationToken cancellationToken)
    {
        await Schedule?.Shutdown(cancellationToken)!;
        Schedule?.Clear(cancellationToken);
    }
}
相关推荐
_Jonas3 小时前
.net framework开发环境正式环境配置文件的切换
.net·wpf
Y3815326622 天前
C# 调用谷歌搜索 API:HttpClient 与 System.Text.Json 实战
搜索引擎·.net
csdn_aspnet2 天前
.NetCore Webapi 接口验证请求来源
.netcore·ip·token·签名·webapi·cors·sign
qq_410194292 天前
.NET 8.0 下基于 PaddleOCRSharp 的离线文字识别落地指南
算法·.net
唐青枫4 天前
别急着拆服务:C#.NET 微服务架构从边界设计到实战
c#·.net
唐青枫5 天前
别把 Razor 当成几段 HTML:C#.NET Razor Pages、MVC 视图与实战详解
c#·.net
宝桥南山5 天前
Microsoft Fabric - 简单尝试一下Microsoft Fabric .NET SDK
microsoft·微软·.net·.netcore·powerbi·fabric
Lost of 程序猿5 天前
.NET 10 船端单机部署与离线升级实战:从闪退事故到无感回滚
c#·asp.net·.net
慧都小妮子5 天前
Word/Excel/PPT 如何稳定导出 Markdown?文档 SDK 三线能力拆解
.net·markdown·知识库·aspose·rag·文档转换·文档互操作
唐青枫6 天前
对象到底住在哪里?C#.NET 托管堆从分配、GC 到内存排查
c#·.net