C# Academy · 강의

Quartz.NET 예약 작업

Quartz.NET으로 작업과 트리거를 정의하고 크론 식을 사용하며 ASP.NET Core DI와 통합합니다.

레슨 4/412개 단계

Quartz.NET 예약 작업은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

Quartz.NET을 사용하는 이유

cron 식, 작업 영속성, 클러스터링, 재시도 정책 및 작업 체인이 필요할 때 Quartz.NET은 PeriodicTimer보다 뛰어난 운영 환경용 스케줄러를 제공합니다. 널리 사용되는 Java Quartz 스케줄러를 .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(또는 최신 Quartz의 경우 IAsyncJob)을 구현하고 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");
    }
}

ASP.NET Core에 Quartz 등록

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는 6개 또는 7개 필드로 이루어진 cron 식을 사용합니다: seconds minutes hours day-of-month month day-of-week [year]. Quartz cron은 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을 통해 런타임 매개 변수를 작업에 전달합니다. context.JobDetail.JobDataMap을 사용하면 Execute 내부에서 해당 매개 변수에 액세스할 수 있습니다.

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

실전: 여러 작업 스케줄러

서로 다른 일정으로 실행되는 여러 작업을 포함하고, 모든 서비스에 DI를 사용하는 운영 환경용 Quartz 구성입니다.

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

빠른 확인

Quartz.NET 작업에 [DisallowConcurrentExecution] 특성을 적용하면 어떤 동작을 합니까?

복습: Quartz.NET 예약 작업

핵심 요점:

  • Quartz.NET: cron, 영속성 및 클러스터링을 지원하는 운영 환경용 스케줄러
  • IJob을 구현하고 Execute 메서드를 정의하여 작업을 만듭니다
  • AddQuartz + AddQuartzHostedService로 등록하며 작업은 DI를 인식합니다
  • cron 형식: 초 분 시 일자 월 요일 — 초가 먼저 나오는 점에 유의합니다
  • [DisallowConcurrentExecution]: 다시 실행하기 전에 현재 실행이 완료될 때까지 기다립니다
  • JobDataMap을 사용하여 런타임 매개 변수를 작업에 전달합니다
무료로 시작

AI 튜터와 함께 C#을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
93
레슨
346

자주 묻는 질문

“Quartz.NET 예약 작업” 강의는 무료인가요?

네 — “Quartz.NET 예약 작업” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“Quartz.NET 예약 작업”에서 뭘 배우나요?

Quartz.NET으로 작업과 트리거를 정의하고 크론 식을 사용하며 ASP.NET Core DI와 통합합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“Quartz.NET 예약 작업” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. IHostedService와 BackgroundService
  2. Worker Service 프로젝트
  3. 주기적 작업과 타이머
  4. Quartz.NET 예약 작업
← C# Academy(으)로 돌아가기