งานตามกำหนดเวลาด้วย Quartz.NET
กำหนดงานและทริกเกอร์ด้วย Quartz.NET ใช้นิพจน์ cron และผสานการทำงานกับ DI ของ ASP.NET Core
งานตามกำหนดเวลาด้วย Quartz.NET เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน 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 (หรือ 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 โดยกำหนดค่างานและตัวกระตุ้นไว้ใน 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);ไวยากรณ์นิพจน์ Cron
Quartz ใช้นิพจน์ cron ที่มี 6 หรือ 7 ช่อง: seconds minutes hours day-of-month month day-of-week [year] cron ของ Quartz แตกต่างจาก cron ของ Unix เล็กน้อย โดยวางวินาทีไว้ช่องแรก
// 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” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “งานตามกำหนดเวลาด้วย Quartz.NET”
กำหนดงานและทริกเกอร์ด้วย Quartz.NET ใช้นิพจน์ cron และผสานการทำงานกับ DI ของ ASP.NET Core คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “งานตามกำหนดเวลาด้วย Quartz.NET” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- IHostedService และ BackgroundService
- โครงการ Worker Service
- งานตามช่วงเวลาและตัวจับเวลา
- งานตามกำหนดเวลาด้วย Quartz.NET