0Pricing
C# Academy · Lezione

Processi pianificati con Quartz.NET

Definisca job e trigger con Quartz.NET, usi espressioni cron e integri il tutto con la DI di ASP.NET Core.

Processi pianificati con Quartz.NET è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.

Perché Quartz.NET?

Quando sono necessarie espressioni cron, persistenza dei job, clustering, criteri di retry e catene di job, Quartz.NET offre uno scheduler adatto alla produzione, con funzionalità superiori a quelle di PeriodicTimer. È il porting .NET del noto scheduler Java Quartz.

Installazione di Quartz.NET

Aggiunga i pacchetti Quartz e Quartz.AspNetCore. L'integrazione con ASP.NET registra automaticamente lo scheduler come servizio ospitato.

# 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

Definizione di un job

Implementi IJob (oppure IAsyncJob nelle versioni più recenti di Quartz) con un metodo Execute. Il contesto del job fornisce i dati di runtime e le informazioni sul trigger corrente.

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

Registrazione di Quartz in ASP.NET Core

Utilizzi AddQuartz per configurare lo scheduler e AddQuartzHostedService per eseguirlo come IHostedService. I job e i trigger vengono configurati nella 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);

Sintassi delle espressioni cron

Quartz utilizza un'espressione cron composta da 6 o 7 campi: secondi minuti ore giorno-del-mese mese giorno-della-settimana [anno]. Il cron di Quartz è leggermente diverso da quello Unix: i secondi vengono per primi.

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

Trigger semplici

Per le pianificazioni basate su intervalli che non richiedono la complessità di cron, utilizzi trigger semplici con 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

Passi i parametri di runtime ai job tramite JobDataMap. Vi acceda all'interno di Execute tramite 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] impedisce l'avvio di una nuova istanza del job mentre quella precedente è ancora in esecuzione. È essenziale per i job che accedono a risorse condivise.

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

Gestione delle eccezioni e retry

Racchiuda il codice del job in try/catch. Generi JobExecutionException per indicare a Quartz di rieseguire il job immediatamente o dopo un ritardo.

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

Caso reale: scheduler con più job

Una configurazione Quartz per la produzione con più job a diverse frequenze, tutti con DI per i servizi.

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

Verifica rapida

Che cosa fa l'attributo [DisallowConcurrentExecution] applicato a un job Quartz.NET?

Riepilogo: job pianificati con Quartz.NET

Punti chiave:

  • Quartz.NET: scheduler adatto alla produzione con cron, persistenza e clustering
  • Definisca i job implementando IJob con un metodo Execute
  • Registri il servizio con AddQuartz + AddQuartzHostedService; i job supportano DI
  • Formato cron: secondi minuti ore giorno-del-mese mese giorno-della-settimana — tenga presente che i secondi vengono per primi
  • [DisallowConcurrentExecution]: attende il completamento dell'esecuzione corrente prima di una nuova esecuzione
  • Utilizzi JobDataMap per passare parametri di runtime ai job

Domande Frequenti

La lezione «Processi pianificati con Quartz.NET» è gratuita?

Sì — il testo completo di «Processi pianificati con Quartz.NET» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.

Cosa imparerò in «Processi pianificati con Quartz.NET»?

Definisca job e trigger con Quartz.NET, usi espressioni cron e integri il tutto con la DI di ASP.NET Core. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Processi pianificati con Quartz.NET»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. IHostedService e BackgroundService
  2. Progetti Worker Service
  3. Attività periodiche e timer
  4. Processi pianificati con Quartz.NET
← Torna a C# Academy