cron-scheduling
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCron Scheduling
Cron 调度
Cron Expression Syntax
Cron 表达式语法
┌─────── minute (0-59)
│ ┌────── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌──── month (1-12)
│ │ │ │ ┌─── day of week (0-7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * *| Expression | Schedule |
|---|---|
| Every hour |
| Every 15 minutes |
| Weekdays at 9:00 AM |
| First day of month, midnight |
| Every 6 hours |
┌─────── minute (0-59)
│ ┌────── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌──── month (1-12)
│ │ │ │ ┌─── day of week (0-7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * *| 表达式 | 调度规则 |
|---|---|
| 每小时一次 |
| 每15分钟一次 |
| 工作日上午9点 |
| 每月1日午夜 |
| 每6小时一次 |
Node.js (node-cron)
Node.js (node-cron)
typescript
import cron from 'node-cron';
// Run every day at 2:00 AM
cron.schedule('0 2 * * *', async () => {
console.log('Running daily cleanup...');
await cleanupExpiredSessions();
}, {
timezone: 'America/New_York',
});
// Run every 5 minutes
cron.schedule('*/5 * * * *', async () => {
await syncExternalData();
});typescript
import cron from 'node-cron';
// Run every day at 2:00 AM
cron.schedule('0 2 * * *', async () => {
console.log('Running daily cleanup...');
await cleanupExpiredSessions();
}, {
timezone: 'America/New_York',
});
// Run every 5 minutes
cron.schedule('*/5 * * * *', async () => {
await syncExternalData();
});With Distributed Locking (prevent duplicate runs)
结合分布式锁(防止重复执行)
typescript
import { Redlock } from 'redlock';
const redlock = new Redlock([redis]);
cron.schedule('0 * * * *', async () => {
let lock;
try {
lock = await redlock.acquire(['cron:hourly-report'], 60000);
await generateHourlyReport();
} catch (err) {
if (err instanceof Redlock.LockError) return; // Another instance has the lock
throw err;
} finally {
await lock?.release();
}
});typescript
import { Redlock } from 'redlock';
const redlock = new Redlock([redis]);
cron.schedule('0 * * * *', async () => {
let lock;
try {
lock = await redlock.acquire(['cron:hourly-report'], 60000);
await generateHourlyReport();
} catch (err) {
if (err instanceof Redlock.LockError) return; // Another instance has the lock
throw err;
} finally {
await lock?.release();
}
});Spring @Scheduled (Java)
Spring @Scheduled (Java)
java
@Component
@EnableScheduling
public class ScheduledTasks {
@Scheduled(cron = "0 0 2 * * *") // Daily at 2 AM
public void dailyCleanup() {
sessionRepo.deleteExpired();
}
@Scheduled(fixedRate = 300000) // Every 5 minutes
public void syncData() {
externalService.sync();
}
@Scheduled(fixedDelay = 60000) // 60s after last completion
public void processQueue() {
queueService.processNext();
}
}java
@Component
@EnableScheduling
public class ScheduledTasks {
@Scheduled(cron = "0 0 2 * * *") // Daily at 2 AM
public void dailyCleanup() {
sessionRepo.deleteExpired();
}
@Scheduled(fixedRate = 300000) // Every 5 minutes
public void syncData() {
externalService.sync();
}
@Scheduled(fixedDelay = 60000) // 60s after last completion
public void processQueue() {
queueService.processNext();
}
}Distributed Scheduling (ShedLock)
分布式调度(ShedLock)
java
@Scheduled(cron = "0 */10 * * * *")
@SchedulerLock(name = "syncInventory", lockAtLeastFor = "5m", lockAtMostFor = "10m")
public void syncInventory() {
inventoryService.syncAll();
}java
@Scheduled(cron = "0 */10 * * * *")
@SchedulerLock(name = "syncInventory", lockAtLeastFor = "5m", lockAtMostFor = "10m")
public void syncInventory() {
inventoryService.syncAll();
}Python (APScheduler)
Python (APScheduler)
python
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
scheduler = AsyncIOScheduler()
@scheduler.scheduled_job(CronTrigger(hour=2, minute=0))
async def daily_cleanup():
await cleanup_expired_sessions()
@scheduler.scheduled_job('interval', minutes=5)
async def sync_data():
await sync_external_data()
scheduler.start()python
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
scheduler = AsyncIOScheduler()
@scheduler.scheduled_job(CronTrigger(hour=2, minute=0))
async def daily_cleanup():
await cleanup_expired_sessions()
@scheduler.scheduled_job('interval', minutes=5)
async def sync_data():
await sync_external_data()
scheduler.start()Anti-Patterns
反模式
| Anti-Pattern | Fix |
|---|---|
| Cron on multiple instances without locking | Use distributed lock (Redlock, ShedLock) |
| Long-running cron blocks next run | Use job queue for heavy work |
| No error handling in cron | Wrap in try-catch, log errors, alert |
| Hardcoded schedule | Use environment variable or config |
| No monitoring of cron execution | Log start/end times, track failures |
| 反模式 | 修复方案 |
|---|---|
| 多实例部署时无锁的Cron任务 | 使用分布式锁(Redlock、ShedLock) |
| 长时间运行的Cron任务阻塞下一次执行 | 针对繁重任务使用任务队列 |
| Cron任务中无错误处理 | 包裹try-catch、记录错误、设置告警 |
| 硬编码调度规则 | 使用环境变量或配置文件 |
| 未监控Cron任务执行情况 | 记录任务开始/结束时间、追踪失败情况 |
Production Checklist
生产环境检查清单
- Distributed locking for multi-instance deployments
- Error handling with alerting
- Execution time monitoring
- Timezone explicitly set
- Graceful shutdown (finish current job)
- Cron expressions documented
- 多实例部署时使用分布式锁
- 带告警的错误处理
- 执行时间监控
- 显式设置时区
- 优雅关闭(完成当前任务)
- 文档化Cron表达式