ふくふくHukuhuku Inc.
EP.36Data Fetch 9分公開: 2026-09-02

定期実行を組む ── 手元の cron から始めない

自分のパソコンで cron を回すと、休んだ日にデータが欠けます。実行ログも残りません。最初から他の場所で回すほうが、結局は楽になります。

#cron#運用#自動化
執筆 / 監修
松尾 亮合同会社ふくふく 代表社員

データ基盤・データパイプライン構築 / BI / 生成 AI 活用支援を専門とするエンジニア (28 年)。 本記事は AI 利用ポリシーに基づき、生成 AI の補助で執筆 → 人間が監修・編集して公開しています。

プロフィール詳細
シェア

取得の処理が書けたら、次は定期実行です。いちばん手軽なのは自分のパソコンで を設定することで、実際それで動きます。ただし、動き続けません。

パソコンを閉じていれば実行されません。持ち出せば実行されません。休みの日は止まります。そして止まったことに誰も気づきません。数週間後に「先月のデータが飛んでいる」と分かる、という壊れ方をします。

取得は、始めた時点で運用が始まります。手元で回すのは試すときだけにして、続けると決めた時点で置き場所を移すのが結果的に楽です。

どこで回すか

選択肢はいくつかありますが、小規模なら が手軽です。サーバを用意する必要がなく、実行ログが残り、失敗すれば通知が飛びます。リポジトリに置いたコードがそのまま動くので、管理する場所も増えません。

処理が重い場合や、社内のネットワークからしか届かないデータを扱う場合は、社内のサーバで回すことになります。その場合も、実行ログを残すことと失敗を知らせることは必須です。

毎朝取得して、失敗したら気づける形にする
YAML
name: fetch-daily
on:  schedule:    # UTC で指定する。日本時間の 6:00 は UTC の 21:00(前日)    - cron: "0 21 * * *"  workflow_dispatch:        # 手動でも回せるようにしておく
jobs:  fetch:    runs-on: ubuntu-latest    timeout-minutes: 30     # 止まらないよう上限を置く    steps:      - uses: actions/checkout@v4      - uses: actions/setup-python@v5        with:          python-version: "3.12"      - run: pip install -r requirements.txt      - name: 取得        env:          API_KEY: ${{ secrets.API_KEY }}        run: python -m fetch.daily      - name: 取得結果を保存        uses: actions/upload-artifact@v4        with:          name: fetched-${{ github.run_id }}          path: data/raw/
時刻の指定は UTC

定期実行の時刻指定は UTC であることがほとんどです。日本時間のつもりで書くと9時間ずれます。しかも夏時間のある地域を基準にしている場合、年に2回さらにずれます。指定した時刻に本当に動いたかを、最初の数日は確認してください。

手で回せるようにしておく

自動実行だけにすると、失敗したときに手で流し直せません。次の定期実行を待つことになり、その間データが欠けたままになります。手動で起動できる口を必ず用意してください。

手で回すときは、期間を指定できるようにしておくと、EP.07 で触れたにそのまま使えます。失敗した日を指定して流し直すだけで復旧できます。

同じ処理が重ならないようにする

前回の実行がまだ終わっていないのに次が始まると、同じデータを二重に取りに行きます。取得が想定より長引いたときに起きるので、普段は問題なく、忙しい日だけ壊れます

EP.07 で扱ったがあれば結果は壊れませんが、相手への要求は倍になります。実行中は次を始めない、という仕組みを入れておくのが確実です。

鍵はから読み、実行の記録は必ず残してください。いつ動いて、何件取れて、どれだけかかったか。この3つが残っていれば、後から異常を追えます。

実行中なら次を始めない。落ちても鍵が残らないようにする
Python
import osfrom contextlib import contextmanagerfrom pathlib import Path
LOCK = Path("data/.fetch.lock")

@contextmanagerdef single_run(lock: Path = LOCK, stale_sec: float = 6 * 3600):    """二重起動を防ぐ。前回が異常終了して鍵が残った場合は、    古すぎる鍵を無視して進む(永久に動かなくなるのを避ける)。"""    lock.parent.mkdir(parents=True, exist_ok=True)
    if lock.exists():        import time
        age = time.time() - lock.stat().st_mtime        if age < stale_sec:            raise RuntimeError(f"実行中の処理がある({age:.0f} 秒前に開始)")        lock.unlink()               # 古すぎる鍵は残骸とみなす
    lock.write_text(str(os.getpid()), encoding="utf-8")    try:        yield    finally:        lock.unlink(missing_ok=True)

実行の間隔は控えめに

更新が1日1回のデータを1時間ごとに取りに行っても、得られるものはありません。相手の更新頻度に合わせるのが基本です。頻度を上げるのは、必要だと分かってからで十分です。

また、多くの処理を同じ時刻に集中させないでください。全部が0時ちょうどに動くと、失敗したときにまとめて失敗します。少しずつずらして配置するだけで、原因の切り分けが楽になります。

定期実行を組んだら、必ず数日は結果を目で確認してください。動いているつもりで動いていない、という状態がいちばん高くつきます。次回は、その確認を自動化する話をします。

定期実行に載せた瞬間から、それは運用対象になります。作った人がいなくなっても回り続ける必要があるので、置き場所と記録は最初に決めておいてください。

最初の数日で確認すべきなのは、指定した時刻に本当に動いたか、件数が想定どおりか、所要時間が上限に近づいていないかの3つです。ここを見ておけば、後から慌てる場面が減ります。

手元で試すのは悪いことではありません。問題は、試したものがそのまま本番の運用になってしまうことです。続けると決めた時点で、置き場所を移す判断をしてください。

実行の記録は、うまくいっている間は誰も見ません。見るのは壊れたときです。だからこそ、壊れる前から残しておく必要があります。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp