Плановые задания Quartz.NET
Определяйте задания и триггеры с помощью Quartz.NET, используйте выражения cron и интегрируйте их с DI ASP.NET Core.
«Плановые задания Quartz.NET» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Зачем нужен Quartz.NET
Когда Вам нужны выражения cron, сохранение заданий, кластеризация, политики повторных попыток и цепочки заданий, Quartz.NET предоставляет планировщик промышленного уровня, превосходящий возможности PeriodicTimer. Это порт популярного планировщика Quartz для Java на платформу .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 (или IAsyncJob в новых версиях Quartz), добавив метод 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");
}
}Регистрация Quartz в ASP.NET Core
Используйте AddQuartz для настройки планировщика и AddQuartzHostedService, чтобы запустить его как IHostedService. Задания и триггеры настраиваются в лямбда-выражении.
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 использует выражение cron из 6 или 7 полей: seconds minutes hours day-of-month month day-of-week [year]. Синтаксис cron в Quartz немного отличается от 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, сохранения данных и кластеризации
- Определяйте задания, реализуя IJob с методом Execute
- Регистрируйте их с помощью AddQuartz + AddQuartzHostedService; задания поддерживают DI
- Формат cron: секунды, минуты, часы, день месяца, месяц, день недели — обратите внимание, что секунды идут первыми
[DisallowConcurrentExecution]: дожидается завершения текущего выполнения перед новым запуском- Используйте JobDataMap для передачи заданиям параметров времени выполнения
Часто задаваемые вопросы
Урок «Плановые задания Quartz.NET» бесплатный?
Да — полный текст урока «Плановые задания Quartz.NET» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Плановые задания Quartz.NET»?
Определяйте задания и триггеры с помощью Quartz.NET, используйте выражения cron и интегрируйте их с DI ASP.NET Core. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Плановые задания Quartz.NET»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- IHostedService и BackgroundService
- Проекты рабочих служб
- Периодические задачи и таймеры
- Плановые задания Quartz.NET