C# Academy · Lekcja

Zaplanowane zadania Quartz.NET

Definiuj zadania i wyzwalacze za pomocą Quartz.NET, używaj wyrażeń cron i integruj rozwiązanie z DI ASP.NET Core.

Lekcja 4 z 412 kroki

Zaplanowane zadania Quartz.NET to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Dlaczego Quartz.NET?

Gdy potrzebujesz wyrażeń cron, trwałości zadań, klastrowania, zasad ponawiania i łańcuchów zadań — Quartz.NET zapewnia gotowy do użycia w produkcji harmonogram wykraczający poza możliwości PeriodicTimer. Jest to port popularnego harmonogramu Quartz z języka Java na platformę .NET.

Instalowanie Quartz.NET

Dodaj pakiety Quartz i Quartz.AspNetCore. Integracja z ASP.NET automatycznie rejestruje scheduler jako usługę hostowaną.

# 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

Definiowanie zadania

Zaimplementuj IJob (lub IAsyncJob w nowszych wersjach Quartz) z metodą Execute. Kontekst zadania udostępnia dane środowiska uruchomieniowego oraz informacje o bieżącym wyzwalaczu.

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");
    }
}

Rejestrowanie Quartz w ASP.NET Core

Użyj AddQuartz, aby skonfigurować scheduler, oraz AddQuartzHostedService, aby uruchomić go jako IHostedService. Zadania i wyzwalacze konfiguruje się w lambdzie.

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);

Składnia wyrażeń cron

Quartz używa 6- lub 7-polowego wyrażenia cron: seconds minutes hours day-of-month month day-of-week [year]. Cron w Quartz nieco różni się od crona w systemie Unix — sekundy znajdują się na początku.

// 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

Proste wyzwalacze

W przypadku harmonogramów opartych na interwałach, które nie wymagają złożoności crona, użyj prostych wyzwalaczy z 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)));

Job Data Map

Przekazuj parametry środowiska uruchomieniowego do zadań za pomocą JobDataMap. Uzyskuj do nich dostęp wewnątrz Execute przez 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] zapobiega uruchomieniu nowej instancji zadania, gdy poprzednia nadal działa. Jest to niezbędne w przypadku zadań uzyskujących dostęp do współdzielonych zasobów.

[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.

Obsługa wyjątków i ponawianie

Umieść kod zadania w bloku try/catch. Rzuć JobExecutionException, aby poinformować Quartz, że ma natychmiast ponowić zadanie lub zrobić to po opóźnieniu.

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
    }
}

Praktyczny przykład: scheduler z wieloma zadaniami

Produkcyjna konfiguracja Quartz z wieloma zadaniami wykonywanymi według różnych harmonogramów, korzystającymi ze wstrzykiwania zależności dla usług.

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 * * ?"));
});

Szybkie sprawdzenie

Co robi atrybut [DisallowConcurrentExecution] umieszczony na zadaniu Quartz.NET?

Podsumowanie: zaplanowane zadania Quartz.NET

Najważniejsze informacje:

  • Quartz.NET: gotowy do użycia w produkcji scheduler z obsługą crona, trwałości i klastrowania
  • Definiuj zadania, implementując IJob z metodą Execute
  • Rejestruj za pomocą AddQuartz + AddQuartzHostedService; zadania obsługują DI
  • Format crona: seconds minutes hours dom month dow — sekundy znajdują się na początku
  • [DisallowConcurrentExecution]: przed ponownym uruchomieniem zaczekaj na zakończenie bieżącego wykonania
  • Używaj JobDataMap do przekazywania parametrów środowiska uruchomieniowego do zadań
Bezpłatny start

Ucz się C# dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
93
Lekcje
346

Często zadawane pytania

Czy lekcja „Zaplanowane zadania Quartz.NET” jest bezpłatna?

Tak — pełny tekst „Zaplanowane zadania Quartz.NET” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Zaplanowane zadania Quartz.NET”?

Definiuj zadania i wyzwalacze za pomocą Quartz.NET, używaj wyrażeń cron i integruj rozwiązanie z DI ASP.NET Core. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Zaplanowane zadania Quartz.NET”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. IHostedService i BackgroundService
  2. Projekty Worker Service
  3. Zadania okresowe i timery
  4. Zaplanowane zadania Quartz.NET
← Powrót do C# Academy