cron-scheduling

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cron 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)
│ │ │ │ │
* * * * *
ExpressionSchedule
0 * * * *
Every hour
*/15 * * * *
Every 15 minutes
0 9 * * 1-5
Weekdays at 9:00 AM
0 0 1 * *
First day of month, midnight
0 */6 * * *
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)
│ │ │ │ │
* * * * *
表达式调度规则
0 * * * *
每小时一次
*/15 * * * *
每15分钟一次
0 9 * * 1-5
工作日上午9点
0 0 1 * *
每月1日午夜
0 */6 * * *
每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-PatternFix
Cron on multiple instances without lockingUse distributed lock (Redlock, ShedLock)
Long-running cron blocks next runUse job queue for heavy work
No error handling in cronWrap in try-catch, log errors, alert
Hardcoded scheduleUse environment variable or config
No monitoring of cron executionLog 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表达式