Lập lịch tác vụ với TypeScript và thư viện node-schedule
Trong bài viết này, chúng ta sẽ tìm hiểu cách tạo một trình lập lịch tác vụ đơn giản bằng TypeScript và thư viện node-schedule. Đây là một công cụ hữu ích cho việc quản lý và chạy các tác vụ định kỳ trong ứng dụng Node.js của bạn.
Giới thiệu về node-schedule
Thư viện node-schedule cho phép bạn lập lịch các tác vụ với cú pháp tương tự như cron. Bạn có thể chỉ định lịch trình cho các tác vụ dưới dạng chuỗi cron hoặc ngày giờ cụ thể. Điều này rất thích hợp cho các tác vụ như gửi email tự động, làm sạch cơ sở dữ liệu, hoặc bất kỳ hành động nào cần được thực hiện định kỳ.
Cài đặt thư viện
Trước tiên, bạn cần cài đặt thư viện cần thiết. Mở terminal và chạy lệnh sau:
bash
npm install node-schedule @types/node-schedule
Cấu trúc mã nguồn
Dưới đây là mã nguồn cho một trình lập lịch đơn giản:
typescript
import * as schedule from 'node-schedule';
import { Job } from 'node-schedule';
interface TaskConfig {
name: string;
schedule: string | Date;
task: () => Promise<void> | void;
enabled?: boolean;
}
class TaskScheduler {
private jobs: Map<string, Job> = new Map();
/**
* Lập lịch một tác vụ với cú pháp giống cron hoặc ngày cụ thể
* @param config Cấu hình tác vụ
* @returns Instance Job
*/
scheduleTask(config: TaskConfig): Job | null {
if (!config.enabled && config.enabled !== undefined) {
console.log(`Tác vụ ${config.name} đã bị vô hiệu, bỏ qua...`);
return null;
}
try {
const job = schedule.scheduleJob(config.name, config.schedule, async () => {
console.log(`[${new Date().toISOString()}] Thực hiện tác vụ: ${config.name}`);
try {
await config.task();
console.log(`[${new Date().toISOString()}] Tác vụ đã hoàn thành: ${config.name}`);
} catch (error) {
console.error(`[${new Date().toISOString()}] Tác vụ thất bại: ${config.name}`, error);
}
});
if (job) {
this.jobs.set(config.name, job);
console.log(`Tác vụ đã được lập lịch: ${config.name} - Lần chạy tiếp theo: ${job.nextInvocation()}`);
}
return job;
} catch (error) {
console.error(`Lập lịch tác vụ thất bại: ${config.name}`, error);
return null;
}
}
/**
* Lập lịch nhiều tác vụ cùng một lúc
* @param configs Mảng cấu hình tác vụ
*/
scheduleTasks(configs: TaskConfig[]): void {
configs.forEach(config => this.scheduleTask(config));
}
/**
* Hủy một tác vụ cụ thể
* @param taskName Tên tác vụ cần hủy
*/
cancelTask(taskName: string): boolean {
const job = this.jobs.get(taskName);
if (job) {
job.cancel();
this.jobs.delete(taskName);
console.log(`Tác vụ đã bị hủy: ${taskName}`);
return true;
}
console.warn(`Không tìm thấy tác vụ: ${taskName}`);
return false;
}
/**
* Hủy tất cả các tác vụ đã lập lịch
*/
cancelAllTasks(): void {
this.jobs.forEach((job, name) => {
job.cancel();
console.log(`Tác vụ đã bị hủy: ${name}`);
});
this.jobs.clear();
}
/**
* Lấy thông tin về tất cả các tác vụ đã lập lịch
*/
getTasksInfo(): Array<{name: string, nextRun: Date | null}> {
const tasksInfo: Array<{name: string, nextRun: Date | null}> = [];
this.jobs.forEach((job, name) => {
tasksInfo.push({
name,
nextRun: job.nextInvocation()
});
});
return tasksInfo;
}
/**
* Lập lịch lại một tác vụ đã tồn tại
* @param taskName Tên tác vụ cần lập lịch lại
* @param newSchedule Lịch trình mới (cron hoặc ngày)
*/
rescheduleTask(taskName: string, newSchedule: string | Date): boolean {
const job = this.jobs.get(taskName);
if (job) {
const success = job.reschedule(newSchedule);
if (success) {
console.log(`Tác vụ đã được lập lịch lại: ${taskName} - Lần chạy tiếp theo: ${job.nextInvocation()}`);
}
return success;
}
console.warn(`Không tìm thấy tác vụ: ${taskName}`);
return false;
}
/**
* Tắt máy một cách an toàn - hủy tất cả các tác vụ
*/
shutdown(): void {
console.log('Đang tắt trình lập lịch...');
this.cancelAllTasks();
schedule.gracefulShutdown();
}
}
Tính năng chính của mã nguồn này:
- Kiểm tra kiểu: Hỗ trợ TypeScript hoàn toàn với các interface và kiểu dữ liệu chính xác.
- Lập lịch linh hoạt: Hỗ trợ nhiều định dạng lập lịch:
- Cú pháp giống cron (
'0 9 * * *'cho mỗi ngày lúc 9 giờ sáng) - Ngày cụ thể (
new Date()) RecurrenceRulecho các mẫu phức tạp.
- Cú pháp giống cron (
- Quản lý tác vụ:
- Lập lịch một hoặc nhiều tác vụ.
- Hủy tác vụ cụ thể hoặc tất cả.
- Lập lịch lại các tác vụ đã tồn tại.
- Kích hoạt/vô hiệu hóa các tác vụ.
- Lấy thông tin về các tác vụ đã lập lịch.
- Xử lý lỗi: Có xử lý lỗi với logging chi tiết.
- Tắt máy an toàn: Dọn dẹp đúng cách khi quá trình dừng lại.
Tham khảo nhanh về định dạng cron
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │
│ │ │ │ │ └ ngày trong tuần (0 - 7) (0 hoặc 7 là Chủ nhật)
│ │ │ │ └───── tháng (1 - 12)
│ │ │ └────────── ngày trong tháng (1 - 31)
│ │ └─────────────── giờ (0 - 23)
│ └──────────────────── phút (0 - 59)
└───────────────────────── giây (0 - 59, tùy chọn)
Các mẫu thông dụng:
'*/5 * * * *'- Mỗi 5 phút.'0 */2 * * *'- Mỗi 2 giờ.'0 9-17 * * 1-5'- Mỗi giờ từ 9 giờ sáng đến 5 giờ chiều, từ Thứ Hai đến Thứ Sáu.'0 0 1 * *'- Ngày đầu tiên của mỗi tháng lúc giữa đêm.
Ví dụ sử dụng
Dưới đây là ví dụ về cách sử dụng lớp TaskScheduler:
typescript
// Khởi tạo trình lập lịch
const scheduler = new TaskScheduler();
// Các tác vụ ví dụ
const exampleTasks: TaskConfig[] = [
{
name: 'daily-report',
schedule: '0 9 * * *', // Mỗi ngày lúc 9:00 sáng
task: async () => {
console.log('Đang tạo báo cáo hàng ngày...');
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Báo cáo hàng ngày đã được tạo thành công');
},
enabled: true
},
{
name: 'database-cleanup',
schedule: '0 2 * * 0', // Mỗi Chủ nhật lúc 2:00 sáng
task: async () => {
console.log('Đang bắt đầu dọn dẹp cơ sở dữ liệu...');
await new Promise(resolve => setTimeout(resolve, 2000));
console.log('Dọn dẹp cơ sở dữ liệu đã hoàn tất');
},
enabled: true
},
];
// Lập lịch tất cả các tác vụ
scheduler.scheduleTasks(exampleTasks);
// Hiển thị thông tin các tác vụ đã lập lịch
console.log('\n=== Các tác vụ đã lập lịch ===');
const tasksInfo = scheduler.getTasksInfo();
tasksInfo.forEach(task => {
console.log(`${task.name}: Lần chạy tiếp theo lúc ${task.nextRun}`);
});
// Tắt máy an toàn khi quá trình kết thúc
process.on('SIGINT', () => {
console.log('\nNhận tín hiệu SIGINT, đang tắt máy an toàn...');
scheduler.shutdown();
process.exit(0);
});
Lời kết
Trình lập lịch tác vụ này không chỉ giúp bạn quản lý các tác vụ định kỳ mà còn cho phép bạn xử lý các tác vụ bất đồng bộ một cách dễ dàng. Bạn có thể mở rộng mã nguồn này với các tính năng như lưu trữ tác vụ, logic thử lại, hoặc hệ thống thông báo. Hãy thử nghiệm và tùy chỉnh theo nhu cầu của bạn!
Câu hỏi thường gặp (FAQ)
-
Làm thế nào để lập lịch một tác vụ chỉ chạy một lần?
Bạn có thể truyền một đối tượngDatecụ thể cho thuộc tínhscheduletrong cấu hình tác vụ. -
Thư viện này có hỗ trợ xử lý bất đồng bộ không?
Có,node-schedulehỗ trợ chạy các tác vụ bất đồng bộ mà không gặp vấn đề gì. -
Tôi có thể hủy tất cả các tác vụ đã lập lịch không?
Có, bạn có thể gọi phương thứccancelAllTasks()để hủy tất cả các tác vụ đã lập lịch.
Hy vọng bài viết này sẽ giúp bạn nắm vững cách sử dụng node-schedule để lập lịch các tác vụ trong ứng dụng của mình. Nếu bạn có bất kỳ câu hỏi nào, hãy để lại ý kiến của bạn dưới bài viết này nhé!