0Pricing
C# Academy · 课时

Quartz.NET 计划任务

使用 Quartz.NET 定义任务和触发器,使用 cron 表达式,并与 ASP.NET Core DI 集成。

Quartz.NET 计划任务 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

为什么选择 Quartz.NET

当您需要 cron 表达式、作业持久化、集群、重试策略和作业链时,Quartz.NET 提供了超越 PeriodicTimer 的生产级调度器。它是广受欢迎的 Java Quartz 调度器的 .NET 移植版本。

安装 Quartz.NET

添加 Quartz 和 Quartz.AspNetCore 包。ASP.NET 集成会自动将调度器注册为托管服务。

# Install packages
dotnet add package Quartz
dotnet add package Quartz.AspNetCore

# Optional: persistence (requires Quartz.Serialization.Json too)
# dotnet add package Quartz.Jobs
# dotnet add package Quartz.Plugins

定义作业

实现 IJob(或较新版本 Quartz 中的 IAsyncJob),并提供一个 Execute 方法。作业上下文会提供运行时数据和当前触发器的信息。

using Quartz;

[DisallowConcurrentExecution] // prevent overlapping executions
public class ReportGeneratorJob : IJob
{
    private readonly IReportService _reports;
    private readonly ILogger<ReportGeneratorJob> _logger;

    public ReportGeneratorJob(IReportService r, ILogger<ReportGeneratorJob> l)
    { _reports = r; _logger = l; }

    public async Task Execute(IJobExecutionContext context)
    {
        _logger.LogInformation("Generating report at {Time}", DateTime.UtcNow);
        await _reports.GenerateDailyReportAsync(context.CancellationToken);
        _logger.LogInformation("Report generated");
    }
}

在 ASP.NET Core 中注册 Quartz

使用 AddQuartz 配置调度器,并使用 AddQuartzHostedService 将其作为 IHostedService 运行。作业和触发器在 lambda 中配置。

builder.Services.AddQuartz(q =>
{
    q.UseMicrosoftDependencyInjectionJobFactory();

    var jobKey = new JobKey("ReportGenerator");
    q.AddJob<ReportGeneratorJob>(opts => opts.WithIdentity(jobKey));

    q.AddTrigger(opts => opts
        .ForJob(jobKey)
        .WithIdentity("ReportTrigger")
        .WithCronSchedule("0 0 8 * * ?") // 8:00 AM daily
    );
});

builder.Services.AddQuartzHostedService(q =>
    q.WaitForJobsToComplete = true);

Cron 表达式语法

Quartz 使用包含 6 或 7 个字段的 cron 表达式:seconds minutes hours day-of-month month day-of-week [year]。Quartz cron 与 Unix cron 略有不同——秒位于第一位。

// Quartz cron format: sec min hour dom month dow [year]

"0 0 8 * * ?"     // Every day at 8:00 AM
"0 0/30 9-17 * * ?" // Every 30 min, 9 AM - 5 PM weekdays
"0 0 0 1 * ?"     // First day of every month at midnight
"0 0 6 ? * MON-FRI" // Every weekday at 6 AM
"0 0/5 * * * ?"   // Every 5 minutes

// Tip: use cronmaker.com or crontab.guru to build expressions

简单触发器

对于不需要 cron 复杂性的基于间隔的计划,请使用 WithSimpleSchedule 配置简单触发器。

q.AddTrigger(opts => opts
    .ForJob(jobKey)
    .WithIdentity("CleanupTrigger")
    .StartNow()
    .WithSimpleSchedule(s => s
        .WithIntervalInHours(1)
        .RepeatForever())
);

// Or a one-shot trigger:
q.AddTrigger(opts => opts
    .ForJob(jobKey)
    .WithIdentity("OneShot")
    .StartAt(DateTimeOffset.UtcNow.AddMinutes(5)));

作业数据映射

通过 JobDataMap 向作业传递运行时参数。在 Execute 中,可以通过 context.JobDetail.JobDataMap 访问这些参数。

q.AddJob<EmailJob>(opts => opts
    .WithIdentity("EmailJob")
    .UsingJobData("to", "admin@example.com")
    .UsingJobData("subject", "Daily Digest"));

// Inside the job:
public async Task Execute(IJobExecutionContext context)
{
    var to      = context.JobDetail.JobDataMap.GetString("to");
    var subject = context.JobDetail.JobDataMap.GetString("subject");
    await _mailer.SendAsync(to!, subject!, "body");
}

DisallowConcurrentExecution

[DisallowConcurrentExecution] 可防止在上一个作业实例仍在运行时启动新的实例。对于会访问共享资源的作业,这是必不可少的。

[DisallowConcurrentExecution]
public class InventorySyncJob : IJob
{
    // If a sync takes > 1 minute and triggers every minute,
    // the next trigger is delayed until this one completes

    public async Task Execute(IJobExecutionContext context)
    {
        await SyncInventoryAsync(context.CancellationToken);
    }
}

// Without [DisallowConcurrentExecution], multiple instances
// could run in parallel, causing data conflicts.

异常处理与重试

请使用 try/catch 包装作业代码。抛出 JobExecutionException 可以通知 Quartz 立即重新触发作业,或在延迟后重新触发。

public async Task Execute(IJobExecutionContext context)
{
    try
    {
        await ProcessAsync(context.CancellationToken);
    }
    catch (TransientException ex)
    {
        // Ask Quartz to retry immediately
        var jobException = new JobExecutionException(ex)
        {
            RefireImmediately = true
        };
        throw jobException;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Job failed — not retrying");
        // Don't rethrow — job is done
    }
}

实际案例:多作业调度器

一个生产环境中的 Quartz 配置,其中包含多个按不同计划运行的作业,并且都通过 DI 使用服务。

builder.Services.AddQuartz(q =>
{
    q.UseMicrosoftDependencyInjectionJobFactory();

    // Daily report at 8 AM
    var reportKey = new JobKey("DailyReport");
    q.AddJob<ReportGeneratorJob>(o => o.WithIdentity(reportKey));
    q.AddTrigger(o => o.ForJob(reportKey)
        .WithCronSchedule("0 0 8 * * ?"));

    // Inventory sync every 15 minutes
    var syncKey = new JobKey("InventorySync");
    q.AddJob<InventorySyncJob>(o => o.WithIdentity(syncKey));
    q.AddTrigger(o => o.ForJob(syncKey)
        .WithSimpleSchedule(s => s
            .WithIntervalInMinutes(15)
            .RepeatForever()));

    // Cache cleanup every night at 2 AM
    var cacheKey = new JobKey("CacheCleanup");
    q.AddJob<CacheCleanupJob>(o => o.WithIdentity(cacheKey));
    q.AddTrigger(o => o.ForJob(cacheKey)
        .WithCronSchedule("0 0 2 * * ?"));
});

快速检查

[DisallowConcurrentExecution] 特性在 Quartz.NET 作业上具有什么作用?

回顾:Quartz.NET 计划作业

关键要点:

  • Quartz.NET:提供 cron、持久化和集群功能的生产级调度器
  • 通过实现带有 Execute 方法的 IJob 来定义作业
  • 使用 AddQuartz + AddQuartzHostedService 注册;作业支持 DI
  • Cron 格式:seconds minutes hours dom month dow — 请注意秒位于第一位
  • [DisallowConcurrentExecution]:等待当前执行完成后再重新触发
  • 使用 JobDataMap 向作业传递运行时参数

常见问题解答

「Quartz.NET 计划任务」课时是免费的吗?

是的 — 「Quartz.NET 计划任务」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「Quartz.NET 计划任务」这节课中我会学到什么?

使用 Quartz.NET 定义任务和触发器,使用 cron 表达式,并与 ASP.NET Core DI 集成。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「Quartz.NET 计划任务」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. IHostedService 与 BackgroundService
  2. Worker Service 项目
  3. 周期性任务与计时器
  4. Quartz.NET 计划任务
← 返回 C# Academy