GitHub Actions 定时任务 schedule 踩坑实录:核心语法与实战技巧
那是一个风雨交加的夜晚,我正在开发一个项目,突然间收到了一连串的紧急通知:生产环境的定时任务没有按时执行,导致数据处理出现延误。当时我心想,这个项目明明已经在 GitHub Actions 里配置了定时任务,为什么会出问题?于是,我开始了漫长的排查之旅,最终在 schedule 配置上找到了根源。今天,我就来和大家聊聊 GitHub Actions 定时任务 schedule 配置的那些事儿。
事故回放
项目上线前,我信心满满地在 GitHub Actions 中配置了定时任务,计划每小时执行一次数据同步脚本。配置完成后,我在本地反复测试,一切都看起来非常完美。然而,事实证明,我忽略了一些细节,导致上线后定时任务频频失败。问题出在哪里呢?让我们先来看看最基本的 schedule 配置语法。
基本语法
在 GitHub Actions 的工作流文件中,schedule 是一个用于定义定时任务的关键词。它使用的是 Cron 表达式,格式如下:
on:
schedule:
- cron: '0 * * * *' # 每小时执行一次
Cron 表达式由五个或六个字段组成,分别代表分钟、小时、日、月、周和年(可选)。每个字段可以使用星号(*)表示任意值,数字表示具体值,范围(-)表示连续值,逗号(,)表示多个离散值,斜杠(/)表示步长值。例如:
0 * * * *表示每小时的第 0 分钟执行一次。30 0 * * *表示每天凌晨 0 点 30 分执行一次。0 0 * * 1表示每周一的凌晨 0 点执行一次。*/10 * * * *表示每 10 分钟执行一次。
这些基本的配置看起来简单,但实际应用中却有不少坑。
坑点 1:时区问题
我的项目上线后,定时任务并没有按照预期的时间执行。经过一番排查,我发现问题出在时区上。GitHub Actions 的 schedule 默认使用的是 UTC 时间,而我当时配置的是本地时间。为了确保定时任务在正确的时间执行,我调整了 Cron 表达式以匹配 UTC 时间。
on:
schedule:
- cron: '0 16 * * *' # UTC 时间 16:00,即北京时间 00:00
坑点 2:GitHub 的定时任务触发限制
在事故排查过程中,我还发现 GitHub 的定时任务有一些限制。例如,schedule 任务的最小精度是 1 分钟,这意味着你不能配置每 30 秒或 45 秒执行一次的任务。此外,GitHub 每个仓库每天只能触发 50 次定时任务,超过这个限制,任务将不会被执行。
on:
schedule:
- cron: '*/10 * * * *' # 每 10 分钟执行一次,符合最小精度要求
坑点 3:环境变量影响
在某些情况下,环境变量可能会影响定时任务的执行。例如,如果你的脚本依赖于某个环境变量,而在定时任务中没有正确设置,脚本可能会失败。为了解决这个问题,你需要确保在 env 部分正确配置了所有需要的环境变量。
on:
schedule:
- cron: '0 * * * *'
jobs:
scheduled-task:
runs-on: ubuntu-latest
env:
API_KEY: ${{ secrets.API_KEY }} # 从 Secrets 中获取 API_KEY
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Run Sync Script
run: node sync.js
坑点 4:依赖外部服务
如果你的定时任务依赖于外部服务,例如数据库或 API,这些服务的可用性和响应时间可能会对定时任务的执行产生影响。在事故中,我在 sync.js 脚本中调用了一个外部 API,但由于 API 一度不可用,导致定时任务失败。为了解决这个问题,我在脚本中添加了重试机制,并在 GitHub Actions 中设置了超时时间。
on:
schedule:
- cron: '0 * * * *'
jobs:
scheduled-task:
runs-on: ubuntu-latest
env:
API_KEY: ${{ secrets.API_KEY }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Run Sync Script with Retry
run: |
node sync.js || { sleep 10 && node sync.js } || { sleep 10 && node sync.js }
timeout-minutes: 10 # 设置超时时间为 10 分钟
坑点 5:调试日志
在事故排查过程中,我发现调试日志对于解决问题至关重要。GitHub Actions 提供了详细的日志输出,但有时你需要更多的信息。为了解决这个问题,我使用了 set-env 动作来设置环境变量,并在脚本中添加了更多的日志输出。
on:
schedule:
- cron: '0 * * * *'
jobs:
scheduled-task:
runs-on: ubuntu-latest
env:
API_KEY: ${{ secrets.API_KEY }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Set Debug Environment
run: echo "DEBUG=true" >> $GITHUB_ENV
- name: Run Sync Script with Debug Logs
run: |
echo "Starting sync script at $(date)"
node sync.js
echo "Sync script completed at $(date)"
常见问题与解决方案
问题 1:定时任务没有触发
如果你发现定时任务没有按时触发,首先检查 cron 表达式是否正确。其次,确保仓库中有至少一次 commit 或 push 操作,因为 GitHub Actions 的 schedule 任务只有在仓库有活动时才会触发。
问题 2:定时任务执行频率过高
如果你的定时任务执行频率过高,可能会超出 GitHub 每天 50 次的限制。建议调整 cron 表达式,降低执行频率。
问题 3:环境变量未设置
确保在 env 部分正确配置了所有需要的环境变量,特别是在使用 Secrets 时。
问题 4:外部服务不可用
在脚本中添加重试机制,并设置合理的超时时间,以应对外部服务偶尔不可用的情况。
问题 5:调试信息不足
在关键步骤中添加更多的日志输出,以便在出现问题时能够快速定位。
实战案例
案例 1:每日凌晨备份数据库
假设你有一个项目,需要每天凌晨 0 点备份数据库。你可以使用以下配置:
name: Daily Database Backup
on:
schedule:
- cron: '0 16 * * *' # UTC 时间 16:00,即北京时间 00:00
jobs:
backup-database:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Backup Database
run: |
echo "Starting database backup at $(date)"
node backup.js
echo "Database backup completed at $(date)"
案例 2:每小时清理缓存
假设你有一个项目的缓存需要每小时清理一次。你可以使用以下配置:
name: Hourly Cache Cleanup
on:
schedule:
- cron: '0 * * * *' # 每小时的第 0 分钟执行
jobs:
clear-cache:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Clear Cache
run: |
echo "Starting cache cleanup at $(date)"
node clear-cache.js
echo "Cache cleanup completed at $(date)"
案例 3:每周一同步数据
假设你有一个项目,需要每周一同步一次数据。你可以使用以下配置:
name: Weekly Data Sync
on:
schedule:
- cron: '0 16 * * 1' # 每周一的北京时间 00:00
jobs:
sync-data:
runs-on: ubuntu-latest
env:
API_KEY: ${{ secrets.API_KEY }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Run Sync Script
run: |
echo "Starting data sync at $(date)"
node sync.js
echo "Data sync completed at $(date)"
小工具推荐
在排查定时任务问题时,我发现了一些非常有用的工具,可以帮助你更高效地配置和调试 GitHub Actions。其中一个我特别推荐的是 Hey Cron。
Hey Cron 的功能
- Cron 表达式生成器:通过中文描述秒转 Cron 表达式,轻松生成复杂的定时任务配置。
- 正则表达式生成器:帮助你在脚本中快速生成和测试正则表达式。
- 中英互译:方便你在阅读和编写英文文档时进行快速翻译。
- JSON 格式化:用于格式化和验证 JSON 数据,确保数据正确无误。
- Base64 编码解码:在需要编码或解码 Base64 的场景下非常有用。
- 时间戳转换:方便你在脚本中处理时间戳。
- JWT 解析:用于解析和验证 JWT 令牌,确保安全性。
如果你在配置 GitHub Actions 的定时任务时遇到任何问题,不妨试试 Hey Cron,它或许能帮到你。希望我的踩坑经历能够帮助你少走弯路,顺利配置定时任务。