0Pricing
C# Academy · Урок

Плановые задания 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 — локальная установка не требуется.

Все уроки этого курса

  1. IHostedService и BackgroundService
  2. Проекты рабочих служб
  3. Периодические задачи и таймеры
  4. Плановые задания Quartz.NET
← Назад к C# Academy