基于 GitHub Actions 的轻量调度器,支持 crontab + 秒级语法,单文件零依赖。
| ⏱️ 秒级精度 | time.sleep(max(0.1, INTERVAL - time.time() % INTERVAL)) 对齐 10 秒边界 |
| 🔒 原子去重 | Git Ref 创建天然原子,双链竞态只有 1 次执行 |
| 🛡️ 持续可用 | 自续期 + 互守护 + 错开空窗,无人值守 |
| 📦 极简代码 | 单文件 tick.py,零外部依赖 |
| 🧪 完备测试 | 305 个单元测试 + 24 小时快进模拟验证 |
唯一配置:Secret
DISPATCH,每行一条,支持注释和空行。cron 使用 UTC 时区。
# crontab 5 字段 — 分 时 日 月 周 仓库 工作流
*/5 * * * * owner/repo check.yml # 每 5 分钟
0 8 * * * owner/repo daily.yml # 每天 08:00
0 9 * * 1 owner/repo weekly.yml # 每周一 09:00
# 秒级语法 — @Ns 仓库 工作流
@10s owner/repo poll.yml # 每 10 秒
字段语法:* 任意 · */5 步进 · 0,30 枚举 · 1-5 范围。秒级最小间隔 10s(= 扫描周期)。
TZ_OFFSET 环境变量控制日志时间显示,默认 0 (UTC),设为 8 显示北京时间。
gh workflow run guard.ymlguard 自动检测并拉起未运行的 tick。也可 git push main 启动。
每轮两条 tick 同时尝试创建同名 Git Ref,GitHub 服务端保证只有一个成功:
tick-a: POST /git/refs → 201 Created ✅ 获锁 → 触发目标
tick-b: POST /git/refs → 422 Conflict ❌ 已存在 → 跳过
| 特性 | 说明 |
|---|---|
| 原子性 | 同名 ref 不可能被创建两次 |
| 无竞态 | 不依赖状态查询,无 API 延迟窗口 |
| 自清理 | 旧 lock tag 每轮自动删除 |
| 场景 | 结果 |
|---|---|
| 双链存活 | 2 竞争锁 → 执行 1 次 ✅ |
| 单链存活 | 1 直接获锁 → 执行 1 次 ✅ |
| 全灭 | git push main 或手动触发任意 tick 🔄 |
| 机制 | 说明 |
|---|---|
| 错开运行 | tick-a 5h / tick-b 5.5h,永不同时空窗 |
| 自动守护 | if: always() 触发 guard.yml,检测并拉起死链 |
| 崩溃自救 | Python 崩溃、超时、正常结束均触发守护 |
| 新版退出 | cancel-in-progress + run_id 检测,新代码推送秒切换 |
| 小时 | 0 | 5 | 5.5 | 10 | 10.5 |
|---|---|---|---|---|---|
| tick-a | 🟢 运行 | 🔄 续期 | 🟢 运行 | 🟢 运行 | 🔄 续期 |
| tick-b | 🟢 运行 | 🟢 运行 | 🔄 续期 | 🟢 运行 | 🟢 运行 |
至少有 1 条链在线
.github/workflows/
├── tick-a.yml 定时器 A (5h)
├── tick-b.yml 定时器 B (5.5h)
└── guard.yml 守护: 检测并拉起死链
tick.py 定时器 + 原子锁 + 调度器
test_tick.py 单元测试 (305 用例, 含快进模拟)
AGENTS.md AI 编码准则
.env 本地任务配置 (与 Secret DISPATCH 同步)
.gitignore 排除 .env
命名规则:
动词_名词,谓词用is_前缀
| 分类 | 函数 | 职责 |
|---|---|---|
| 工具 | gh |
执行 gh CLI 命令 |
gh_api |
调用 GitHub API (GET) | |
| 解析 | match_field |
单个 cron 字段匹配 (*, */N, 逗号, 范围) |
match_cron |
5 字段 cron 表达式匹配,含日/月偏移修正 | |
parse_dispatch |
解析 DISPATCH secret,支持注释和空行 | |
| 判断 | is_expired |
锁过期判断 (cron/秒级/旧格式兼容) |
| 调度 | scan_round |
扫描本轮匹配的任务 (纯函数,无 I/O) |
execute_task |
竞锁 + 触发 + 日志 | |
trigger_workflow |
使用 PAT 跨仓库触发 workflow | |
| 锁 | acquire_lock |
创建 Git Ref 获取分布式锁 |
sanitize_key |
cron 表达式 → 合法 ref 名称 | |
| 维护 | clean_locks / clean_runs |
清理过期锁 / 已完成的 run |
check_update |
检测更新版本,有则退出让位 |
覆盖:纯函数验证、锁过期判断、端到端 DISPATCH 解析、24 小时快进调度模拟。
python3 test_tick.py