cron-job.org で GitHub Actions を正確な時刻に実行する
前回の記事では、GitHub Actions の cron と Chatwork API を使って出退勤メッセージを自動化しました。
仕組み自体はうまく動いていたんですが、しばらく運用していると気になる問題が出てきたんですよね。
cron の実行時刻がズレる。
GitHub Actions の cron は、混雑時に数分〜数十分ほど遅延することがあります。朝 8:55 に設定しているのに、実際にメッセージが届くのが 9:10 だったり、ひどいときは 9:20 過ぎだったり。
出退勤メッセージって、9:00 ちょうどに届いてほしいんですよね。遅れて届くと「寝坊したのかな?」みたいな印象を与えかねないので。
そこで、外部の cron サービス cron-job.org から正確な時刻に GitHub Actions の workflow_dispatch を叩く方式に変えてみました。
目次
cron-job.org とは
cron-job.org は、無料で使える外部 cron サービスです。
指定した URL に HTTP リクエストを定期的に送ってくれるサービスで、1分単位でスケジュールを設定できます。無料枠でもかなり使えるので、今回のような用途にはぴったりですね。
- 無料で利用可能
- 1分単位のスケジュール設定
- HTTP リクエスト(GET / POST など)を送信できる
- ヘッダーやボディのカスタマイズも可能
GitHub Personal Access Token(Fine-grained)の作成
cron-job.org から GitHub Actions のワークフローを起動するには、GitHub の Personal Access Token が必要です。
今回は Fine-grained token(きめ細かいトークン)を作成します。classic token でも動きますが、必要最小限の権限に絞れる Fine-grained の方が安心ですね。
- GitHub の Settings → Developer settings → Personal access tokens → Fine-grained tokens を開く
- Generate new token をクリック
- Token name: わかりやすい名前をつける(例:
cron-job-dispatch) - Expiration: 有効期限を設定(後述の注意点を参照)
- Repository access: Only select repositories で対象リポジトリのみ選択
- Permissions → Repository permissions → Actions: Read and write に設定
- Generate token をクリックしてトークンをコピー
このトークンはあとで cron-job.org の設定に使うので、どこかにメモしておいてください。
workflow_dispatch トリガーの追加
前回の記事で作ったワークフローを修正します。schedule トリガーを削除して、workflow_dispatch だけにする構成にしてみました。
name: Chatwork Scheduled Message
on:
workflow_dispatch: # cron-job.org から呼び出される
jobs:
send-message:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Resolve message
id: resolve
run: |
pip -q install pyyaml
MESSAGE=$(python scripts/resolve-message.py messages/calendar.yml) || exit 0
{
echo "message<<__EOF__"
echo "$MESSAGE"
echo "__EOF__"
} >> "$GITHUB_OUTPUT"
echo "should_send=true" >> "$GITHUB_OUTPUT"
- name: Send Chatwork Message
if: steps.resolve.outputs.should_send == 'true'
run: |
curl -s -X POST \
-H "X-ChatWorkToken: ${{ secrets.CHATWORK_API_TOKEN }}" \
--data-urlencode "body=${{ steps.resolve.outputs.message }}" \
"https://api.chatwork.com/v2/rooms/${{ secrets.CHATWORK_ROOM_ID }}/messages"変更点は on: の部分だけです。schedule を消して workflow_dispatch だけにしました。
これで、外部から API を叩くことでワークフローを起動できるようになります。もちろん GitHub の Actions タブからの手動実行もこれまで通り可能です。
workflow_id の調べ方
cron-job.org の設定で使う workflow_id を調べておきます。GitHub CLI が入っていれば、以下のコマンドで確認できます。
gh workflow list出力例:
Chatwork Scheduled Message active 12345678この 12345678 の部分が workflow_id です。
GitHub CLI がない場合は、API でも確認できます。
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
https://api.github.com/repos/{owner}/{repo}/actions/workflowsもしくは、ワークフローファイル名(chatwork-scheduled-message.yml)をそのまま workflow_id の代わりに使うこともできます。この場合、URL は以下のようになります。
https://api.github.com/repos/{owner}/{repo}/actions/workflows/chatwork-scheduled-message.yml/dispatchescron-job.org の設定
ここからが本題ですね。cron-job.org でジョブを作成していきます。
アカウント作成
cron-job.org にアクセスして、アカウントを作成します。メールアドレスだけで登録できます。
朝の出勤メッセージ用ジョブ
ログインしたら「Cron Jobs」→「Create Cron Job」で新しいジョブを作ります。
設定内容は以下の通りです。
- Title: Morning Message(わかりやすい名前をつける)
- URL:
https://api.github.com/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches - Method: POST
- Schedule: 毎日 8:55 JST(= UTC 23:55 ※前日扱い)
Headers タブで以下の3つを追加します。
Authorization: Bearer ghp_xxxxxxxxxxxxxxxxxxxx
Accept: application/vnd.github+json
Content-Type: application/jsonRequest Body に以下の JSON を設定します。
{"ref": "main"}ref にはワークフローを実行するブランチ名を指定します。通常は main でOKです。
夕方の退勤メッセージ用ジョブ
同じ要領で、夕方用のジョブも作成します。
- Title: Evening Message
- URL: 朝と同じ
- Method: POST
- Schedule: 毎日 18:05 JST(= UTC 9:05)
- Headers: 朝と同じ
- Request Body: 朝と同じ
これで朝と夕方の2つのジョブが設定できました。
実際にやってみた結果
しばらく運用してみた結果をまとめます。
GitHub Actions の cron だけだったとき
- 設定時刻から 5〜15分の遅延が頻繁に発生
- たまに20分以上遅れることも
- 朝のメッセージが 9:10 や 9:15 に届いてしまう
cron-job.org 経由に変えたあと
- ほぼジャストタイムで実行される(誤差は1分以内)
- メッセージが 8:56〜8:57 頃に届くようになった
- 安定して毎日同じ時刻に届く
体感としてはかなり改善されましたね。出退勤メッセージのように「時刻が重要」な用途では、この差は大きいです。
注意点
トークンの有効期限
Fine-grained token に有効期限を設定している場合、期限が切れるとワークフローが起動しなくなります。期限切れの前にトークンを再生成して、cron-job.org 側のヘッダーも更新するのを忘れないようにしましょう。
カレンダーにリマインダーを設定しておくと安心ですね。
cron-job.org の無料枠の制限
無料プランには以下のような制限があります。
- ジョブ数の上限あり(ただし今回のように2〜3個なら問題なし)
- 最短実行間隔は1分
- 実行履歴の保持期間に制限あり
普通に使う分には無料枠で十分ですね。自分は朝と夕方の2ジョブだけなので、まったく問題なく運用できています。
まとめ
- GitHub Actions の cron は混雑時に遅延するため、正確な時刻での実行には向いていない
- cron-job.org から
workflow_dispatchを叩く方式にしたら、ほぼジャストタイムで実行されるようになった - 設定は「トークン作成 → ワークフロー修正 → cron-job.org でジョブ作成」の3ステップだけ
- 無料枠で問題なく運用できている
前回の記事で作った出退勤メッセージの自動化が、これでより実用的になりました。同じように GitHub Actions の cron のズレに困っている方の参考になれば嬉しいです。
今回は以上です!