I. Bối cảnh
Trong nhiều ứng dụng, bạn có thể cần thực hiện các tác vụ định kỳ như cập nhật dữ liệu trong cơ sở dữ liệu vào một thời điểm cụ thể, hoặc gọi một API theo chu kỳ. Thay vì thực hiện thủ công, các tác vụ này có thể được tự động hóa bằng cách sử dụng "lập lịch tác vụ". Có nhiều framework lập lịch tác vụ trên thị trường, và bạn thậm chí có thể tự xây dựng một chương trình đơn giản bằng cách kết hợp bộ hẹn giờ (timer) với dịch vụ Windows. Trong bài viết này, chúng ta sẽ tìm hiểu về Quartz, một framework lập lịch tác vụ mạnh mẽ, mã nguồn mở và nhẹ, hỗ trợ biểu thức cron và nhiều tính năng vượt trội khác.
II. Quartz.NET
1. Các khái niệm cơ bản
| Lập lịch (Scheduler) | Kích hoạt (Trigger) | Công việc (Job) |
|---|---|---|
| Đây là container độc lập nơi Quartz hoạt động. | Xác định quy tắc thời gian để lên lịch một tác vụ. | Container chứa logic thực thi của một tác vụ cụ thể. |
2. Sử dụng cơ bản
- Thêm gói Quartz.NET qua NuGet.
- Tạo một container lập lịch tác vụ (Scheduler).
- Chỉ định công việc (Job) cụ thể cần thực thi và bộ kích hoạt (Trigger).
- Thêm công việc và bộ kích hoạt vào Scheduler và khởi động.
public class QuanLyQuartz
{
public async static void KhoiDong()
{
// Tạo một factory để khởi tạo Scheduler
var factory = new StdSchedulerFactory();
// Tạo một Scheduler - container lập lịch tác vụ
IScheduler lapLich = await factory.GetScheduler();
// Chỉ định công việc cần thực thi
IJobDetail congViecGuiEmail = JobBuilder.Create<CongViecGuiEmail>()
.WithIdentity("congViecGuiEmail", "nhomCongViecGuiEmail")
.WithDescription("Lập lịch gửi email").Build();
// Đặt điều kiện kích hoạt: thực thi mỗi 10 giây
ITrigger kichHoatGuiEmail = TriggerBuilder.Create()
.WithIdentity("kichHoatGuiEmail", "nhomCongViecGuiEmail")
.WithDescription("Quartz.NET")
.WithCronSchedule("0/10 * * * * ?")
.Build();
// Thêm công việc và bộ kích hoạt vào Scheduler
await lapLich.ScheduleJob(congViecGuiEmail, kichHoatGuiEmail);
// Bắt đầu thực thi
await lapLich.Start();
}
}
// Đảm bảo công việc không bị thực thi song song
[DisallowConcurrentExecution]
public class CongViecGuiEmail : IJob
{
// Lớp công việc
public async Task Execute(IJobExecutionContext context)
{
await Task.Run(() =>
{
// Thực hiện logic của công việc
Console.WriteLine($"Đang thực thi công việc: {DateTime.Now}");
});
}
}
III. Truyền tham số
Đôi khi, bạn cần truyền một số tham số vào công việc (Job) để thực hiện các logic xử lý khác nhau. Quartz cung cấp các cách để truyền tham số.
- Truyền tham số qua Job
- Truyền tham số qua Trigger
1. Truyền tham số qua Job và Trigger
Sử dụng JobDataMap.Add để thêm tham số, và lấy giá trị trong công việc bằng context.JobDetail.JobDataMap.GetString.
IJobDetail congViecGuiEmail = JobBuilder.Create<CongViecGuiEmail>().Build();
// Truyền một tham số vào Job
congViecGuiEmail.JobDataMap.Add("thamSoCongViec", "Giá trị từ Job");
ITrigger kichHoatGuiEmail = TriggerBuilder.Create().Build();
// Truyền một tham số vào Trigger
kichHoatGuiEmail.JobDataMap.Add("thamSoKichHoat", "Giá trị từ Trigger");
// Lấy tham số trong công việc
public async Task Execute(IJobExecutionContext context)
{
await Task.Run(() =>
{
// Lấy tham số từ Job
string thamSoCongViec = context.JobDetail.JobDataMap.GetString("thamSoCongViec");
// Lấy tham số từ Trigger
string thamSoKichHoat = context.Trigger.JobDataMap.GetString("thamSoKichHoat");
// Thực hiện logic
Console.WriteLine($"Đang thực thi công việc: {DateTime.Now}");
});
}
IV. Đăng ký trình lắng nghe (Listener) trong Scheduler
Trình lắng nghe là các đối tượng thực thi các hành động khi các sự kiện xảy ra trong scheduler. Có ba loại trình lắng nghe chính:
- Trình lắng nghe Lập lịch (ISchedulerListener): Lắng nghe các sự kiện liên quan đến quá trình lập lịch.
- Trình lắng nghe Kích hoạt (ITriggerListener): Lắng nghe các sự kiện liên quan đến bộ kích hoạt.
- Trình lắng nghe Công việc (IJobListener): Lắng nghe các sự kiện trong vòng đời của một Job.
1. Triển khai trình lắng nghe
Ví dụ dưới đây triển khai một trình lắng nghe công việc (IJobListener). Việc triển khai các trình lắng nghe khác cũng tương tự.
- Tạo trình lắng nghe tùy chỉnh bằng cách kế thừa từ giao diện IJobListener và triển khai các phương thức.
- Thêm trình lắng nghe tùy chỉnh vào trình quản lý lắng nghe của scheduler.
// Triển khai trình lắng nghe
public class NgheNghiepCongViecTuDinhNghia : IJobListener
{
public string Name => "NgheNghiepCongViecTuDinhNghia";
}
// Thêm vào trình quản lý lắng nghe
lapLich.ListenerManager.AddJobListener(new NgheNghiepCongViecTuDinhNghia());
V. Giao diện quản lý trực quan
Để xem thông tin về các Job đang chạy, bạn có thể sử dụng các công cụ quản lý trực quan.
- Tạo một dự án web hoặc console mới.
- Thêm các gói Quartz và CrystalQuartz.Remote vào dự án web qua NuGet.
- Cấu hình
StdSchedulerFactorytrong bộ lập lịch để chỉ định cổng lắng nghe.
var properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "He Thong Giam Sat Test";
// Cấu hình pool luồng
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "5";
properties["quartz.threadPool.threadPriority"] = "Normal";
// Cấu hình xuất dữ liệu từ xa
properties["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz";
properties["quartz.scheduler.exporter.port"] = "9090";
properties["quartz.scheduler.exporter.bindName"] = "QuartzScheduler";
properties["quartz.scheduler.exporter.channelType"] = "tcp";
var schedulerFactory = new StdSchedulerFactory(properties);
IScheduler _scheduler = await schedulerFactory.GetScheduler();
4. Truy cập vào đường dẫn CrystalQuartzPanel.axd trên cổng đã cấu hình để xem giao diện quản lý.
VI. Cấu hình công việc qua file
Bạn có thể định nghĩa các Job và Trigger không chỉ trong code mà còn bằng cách sử dụng file cấu hình XML.
- Chuẩn bị file cấu hình XML, định nghĩa thông tin Job và Trigger. Đảm bảo file có thuộc tính "Copy Always".
true
<schedule>
<job>
<name>congViecGuiEmail</name>
<group>Nhom Cong Viec Test</group>
<description>This is Test Mail Job</description>
MyApp.Job.MyJob, MyApp
<durable>true</durable>
<recover>false</recover>
</job>
<trigger>
<cron>
<name>kichHoatGuiEmail</name>
<group>nhomCongViecGuiEmail</group>
congViecGuiEmail
Nhom Cong Viec Test
0/15 * * * * ?
</cron>
</trigger>
</schedule>
- Đọc file cấu hình, tạo Job và Trigger tương ứng.
XMLSchedulingDataProcessor xuLyDuLieu = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
// Đọc file cấu hình
await xuLyDuLieu.ProcessFileAndScheduleJobs("~/config/quartz.xml", lapLich);
// Khởi động bộ lập lịch
await lapLich.Start();