$ go run main.go 2025/02/23 16:03:47 cron start 2025/02/23 16:03:47 任务 ID: 1 2025/02/23 16:03:47 INFO start 2025/02/23 16:03:47 INFO schedule now=2025-02-23T16:03:47.035+08:00 entry=1 next=2025-02-23T16:03:52.000+08:00 2025/02/23 16:03:52 INFO wake now=2025-02-23T16:03:52.000+08:00 2025/02/23 16:03:52 INFO run now=2025-02-23T16:03:52.000+08:00 entry=1 next=2025-02-23T16:03:57.000+08:00 江湖十年: 每 5 秒执行的任务, count: 1 2025/02/23 16:03:57 INFO wake now=2025-02-23T16:03:57.001+08:00 2025/02/23 16:03:57 INFO run now=2025-02-23T16:03:57.001+08:00 entry=1 next=2025-02-23T16:04:02.000+08:00 2025/02/23 16:03:57 ERROR panic stack="..." err="第 2 次执行触发 panic" 2025/02/23 16:04:02 INFO wake now=2025-02-23T16:04:02.000+08:00 2025/02/23 16:04:02 INFO run now=2025-02-23T16:04:02.000+08:00 entry=1 next=2025-02-23T16:04:07.000+08:00 江湖十年: 每 5 秒执行的任务, count: 3 2025/02/23 16:04:07 INFO wake now=2025-02-23T16:04:07.000+08:00 2025/02/23 16:04:07 INFO run now=2025-02-23T16:04:07.000+08:00 entry=1 next=2025-02-23T16:04:12.000+08:00 2025/02/23 16:04:12 INFO wake now=2025-02-23T16:04:12.000+08:00 2025/02/23 16:04:12 INFO run now=2025-02-23T16:04:12.000+08:00 entry=1 next=2025-02-23T16:04:17.000+08:00 2025/02/23 16:04:12 INFO skip 2025/02/23 16:04:13 第 4 次执行耗时 6s 江湖十年: 每 5 秒执行的任务, count: 4 2025/02/23 16:04:17 INFO wake now=2025-02-23T16:04:17.001+08:00 江湖十年: 每 5 秒执行的任务, count: 5 2025/02/23 16:04:17 INFO run now=2025-02-23T16:04:17.001+08:00 entry=1 next=2025-02-23T16:04:22.000+08:00 2025/02/23 16:04:21 INFO removed entry=1 2025/02/23 16:04:31 cron done
// Entry 作业实体对象,表示一个被注册进 Cron 执行器中的作业 type Entry struct { // ID 是作业的唯一 ID,可用于查找快照或将其删除 ID EntryID // Schedule 作业的执行计划,应该按照此计划来执行作业 Schedule Schedule // Next 下次运行作业的时间,如果 Cron 尚未启动或无法满足此作业的执行计划,则为 zero time Next time.Time // Prev 是此作业的最后一次运行时间,如果从未运行,则为 zero time Prev time.Time // WrappedJob 作业装饰器,为作业增加新的功能,会在 Schedule 被激活时运行 WrappedJob Job // Job 提交到 Cron 中的作业 Job Job }
EntryID 就是我们调用 c.Remove(id) 时使用的 id。
Cron 最核心的逻辑当然是调度逻辑,其功能主要由 for...select 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
for { select { case now = <-timer.C: // 运行下一次执行时间小于当前时间的所有作业 case newEntry := <-c.add: // 有新的作业加入进来,加入调度 case replyChan := <-c.snapshot: // 获取当前作业列表 case <-c.stop: // 停止调度 case id := <-c.remove: // 移除指定 ID 的作业 }