C# Academy · Lección

Trabajos programados con Quartz.NET

Defina trabajos y triggers con Quartz.NET, use expresiones cron e intégrelo con la DI de ASP.NET Core.

Lección 4 de 412 pasos

Trabajos programados con Quartz.NET es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

¿Por qué Quartz.NET?

Cuando necesita expresiones cron, persistencia de trabajos, agrupación en clústeres, políticas de reintento y cadenas de trabajos, Quartz.NET proporciona un planificador preparado para producción que va más allá de lo que ofrece PeriodicTimer. Es la adaptación para .NET del popular planificador Quartz de Java.

Instalación de Quartz.NET

Añada los paquetes Quartz y Quartz.AspNetCore. La integración con ASP.NET registra automáticamente el planificador como un servicio hospedado.

# 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

Definición de un trabajo

Implemente IJob (o IAsyncJob en las versiones más recientes de Quartz) con un método Execute. El contexto del trabajo proporciona datos de ejecución e información sobre el trigger actual.

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

Registro de Quartz en ASP.NET Core

Utilice AddQuartz para configurar el planificador y AddQuartzHostedService para ejecutarlo como un IHostedService. Los trabajos y los triggers se configuran en la 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);

Sintaxis de las expresiones cron

Quartz utiliza una expresión cron de 6 o 7 campos: seconds minutes hours day-of-month month day-of-week [year]. El cron de Quartz es ligeramente diferente del cron de Unix: los segundos aparecen primero.

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

Triggers simples

Para horarios basados en intervalos sin la complejidad de cron, utilice triggers simples 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)));

JobDataMap

Pase parámetros de ejecución a los trabajos mediante JobDataMap. Acceda a ellos dentro de Execute a través de 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] impide que se inicie una nueva instancia del trabajo mientras una anterior siga ejecutándose. Es esencial para los trabajos que acceden a recursos compartidos.

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

Manejo de excepciones y reintentos

Encierre el código del trabajo en un bloque try/catch. Lance JobExecutionException para indicar a Quartz que vuelva a ejecutar el trabajo inmediatamente o después de un retraso.

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 real: planificador con varios trabajos

Una configuración de Quartz para producción con varios trabajos en diferentes horarios, todos ellos utilizando inyección de dependencias para los servicios.

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

Comprobación rápida

¿Qué hace el atributo [DisallowConcurrentExecution] en un trabajo de Quartz.NET?

Resumen: trabajos programados con Quartz.NET

Aspectos clave:

  • Quartz.NET: planificador preparado para producción con cron, persistencia y agrupación en clústeres
  • Defina trabajos implementando IJob con un método Execute
  • Regístrelos con AddQuartz + AddQuartzHostedService; los trabajos admiten inyección de dependencias
  • Formato cron: seconds minutes hours dom month dow — tenga en cuenta que los segundos aparecen primero
  • [DisallowConcurrentExecution]: espera a que finalice la ejecución actual antes de volver a ejecutar el trabajo
  • Utilice JobDataMap para pasar parámetros de ejecución a los trabajos
Gratis para empezar

Aprende C# con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
93
Lecciones
346

Preguntas frecuentes

¿La lección «Trabajos programados con Quartz.NET» es gratis?

Sí — el texto completo de «Trabajos programados con Quartz.NET» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Trabajos programados con Quartz.NET»?

Defina trabajos y triggers con Quartz.NET, use expresiones cron e intégrelo con la DI de ASP.NET Core. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Trabajos programados con Quartz.NET»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. IHostedService y BackgroundService
  2. Proyectos Worker Service
  3. Tareas periódicas y temporizadores
  4. Trabajos programados con Quartz.NET
← Volver a C# Academy