概要
業務フローの自動化では、処理の起動時刻と起動の契機を設計します。スケジュール起動には Cron、イベント起動には Webhook を使います。両者を必要に応じて組み合わせることで、月次集計などのバッチ処理から問い合わせへの即時対応まで設計できます。
CronとWebhookの特性と使い分け、実装要件、両者を組み合わせた業務フローを5つのパターンで整理します。DigitalBaseが社内AI基盤の構築で実際に採用している設計指針をもとに解説します。
CronとWebhookの違い
両者は処理の起動に使いますが、起動の契機と実装上の注意点が異なります。
| 項目 | Cron | Webhook |
|---|---|---|
| 起動タイミング | 時刻ベース | イベントベース |
| 主な用途 | 定期処理、バッチ | リアルタイム反応 |
| 実装の難しさ | 容易(cron式の定義のみ) | やや複雑(HMAC署名・冪等性) |
| 処理が走るタイミング | 予測可能 | 予測不能(バースト注意) |
| 失敗時の扱い | 次回実行で復旧可能 | リトライ・再送の設計が必要 |
起動の契機で分けると、「決まった時刻に必ず動く」のがCron、「外部から呼び出されたときだけ動く」のがWebhook です。この性質の違いが、後述する実装要件の差につながります。
Cron式の基本
Cronは5つのフィールドで起動タイミングを表現します。
* * * * * │ │ │ │ └─ 曜日 (0-6, 日曜=0) │ │ │ └─── 月 (1-12) │ │ └───── 日 (1-31) │ └─────── 時 (0-23) └───────── 分 (0-59)
業務でよく用いるパターンを以下に示します。
| 用途 | Cron式 |
|---|---|
| 平日朝9時 | 0 9 * * 1-5 |
| 毎月1日0時 | 0 0 1 * * |
| 15分おき | */15 * * * * |
| 営業時間内の毎時0分 | 0 9-18 * * 1-5 |
タイムゾーンは必ず明示します。サーバーのロケール設定に依存させず、スケジューラ側で Asia/Tokyo に固定するのが安全です。設定の差異による起動時刻のずれには注意が必要です。
Webhook受信側の必須要件
Webhookは外部から呼び出される性質上、Cronにはない実装要件を伴います。本番運用では、以下の3点を必須要件としています。
1. HMAC署名検証
受信エンドポイントは外部に公開されるため、正当な送信元からのリクエストであることを署名で検証します。
import hmac import hashlib def verify_signature(payload: bytes, signature: str, secret: str) -> bool: expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature)
比較には必ず hmac.compare_digest を用い、タイミング攻撃を回避します。
2. 冪等性
同じイベントが2回届いても、副作用が1回で済むように設計します。多くの送信元はリトライを行うため、重複配信は例外ではなく前提です。送信元が付与する event_id をキーに処理済み判定を入れ、二重処理を防ぎます。
3. 即時応答 + 非同期処理
Webhookの送信元の多くは「数秒以内に200を返さないとリトライする」仕様です。受信時点では検証と受付のみを行い、重い処理は非同期で実行します。
@app.post("/webhook/incoming") async def receive(event: dict, bg: BackgroundTasks): bg.add_task(process_async, event) return {"status": "accepted"} # すぐに応答を返す
即時応答と後続の非同期処理を組み合わせ、再送による負荷の増大を防ぎます。
実装パターン1:月次経理データ集約(Cron主体)
シナリオ:全国8拠点の生産実績Excelを月初に自動集計し、ダッシュボードに反映します。
[ 毎月1日 7:00 (Cron) ] ↓ [ source_file: 各拠点のSharePoint上のExcelを取得 ] ↓ [ transform_llm: フォーマット差異をLLMで吸収 → 統一スキーマへ正規化 ] ↓ [ transform_aggregate: 拠点別・品目別に集計 ] ↓ [ load_sql: 集計テーブルにupsert ] ↓ [ action_webhook: ダッシュボードのキャッシュ無効化 ]
拠点ごとにExcelの様式が異なるケースは製造業の現場で頻出します。この様式差を機械的なパースで吸収しようとすると保守コストが膨らむため、LLMで統一スキーマへ正規化する工程を挟むのが現実的です。定刻に確実に動かす必要があるため、起動はCronが適しています。
実装パターン2:問い合わせ自動分類(Webhook主体)
シナリオ:メール受信を起点に、内容を即座に分類してSlackへ通知します。緊急案件であれば担当者を自動でアサインします。
[ メール受信 (IMAP IDLE → Webhook) ] ↓ [ HMAC検証 + 冪等性チェック ] ↓ [ transform_llm: 件名+本文を urgent/normal/low に分類し、要約を生成 ] ↓ [ flow_if: urgent ? true → action_slack(#urgent), action_webhook(チケット作成) false → action_slack(#inbox) ]
到着時刻が予測できない問い合わせ対応には、イベント起動のWebhookが適しています。分類と要約をLLMに委ねることで、人手による一次仕分けの負荷を削減できます。
実装パターン3:在庫アラート(Cron + Webhook 連携)
シナリオ:5分おきに在庫を監視し、閾値を割り込んだらWebhookで複数システムへ通知します。
監視は定期処理のためCronで実行し、閾値割れの検知時にのみWebhookで外部へ通知する構成です。同一商品について5分おきに通知が繰り返されないようにします。最後の通知時刻を状態として保存し、一定時間内の重複通知を抑制します。通知状態を管理しない場合、重複通知によって確認作業の負荷が増えます。
実装パターン4:承認フロー(Webhook + Cron督促)
シナリオ:申請受付 → 承認待ち → 期限超過なら督促 → 期限後はエスカレーション、という多段のフローを構成します。
申請の受付はWebhookで即座に処理しますが、「承認待ち」という状態は時間をまたいで永続化する必要があります。承認待ちの案件をDBに due_at(期限)付きで保持し、Cronで定期的に確認して期限超過を検知する構成が基本です。イベント起動と時刻起動を役割分担させることで、状態の遷移を伴う業務プロセスを表現できます。
実装パターン5:日次レポート + リアルタイム反応(ハイブリッド)
シナリオ:通常はCronで日次サマリを送り、重大インシデント発生時にはWebhookで即時通知します。
- 緊急は電話、通常はSlack、サマリはメール、と重要度に応じて通知経路を分ける
- 営業時間内外で通知方法を切り替える
通常時と異常時の通知を同じ経路に集約すると、重要な通知が埋もれます。CronとWebhookを併用しつつ、通知の段階設計を併せて行うことが、実運用での信頼性につながります。
運用上の注意点
運用に向けて、次の点を設計段階で確認します。
Cron関連
- タイムゾーンずれ:サーバーがUTC、表示がJSTという不一致で、想定と異なる時刻に起動する
- ジョブ重複:前回の実行が長引いたとき、次回の起動と並走して同じデータを二重処理する
- 存在しない日付:
0 0 31 * *のような指定は、31日が存在しない月にスキップされる
Webhook関連
- リトライ嵐:受信側が重く200を返せず、送信元が再送を繰り返してさらに負荷が増す
- 署名漏れ:HMAC検証を入れないと、URLを知る第三者が任意にリクエストを送れてしまう
- 順序保証なし:多くのWebhookは配信順序を保証せず、後発のイベントが先に届くことがある
まとめ
業務フロー自動化の多くは、CronとWebhookの組み合わせで設計できます。設計上の要点は次の3点です。
- 時刻起動はCron、イベント起動はWebhook:両者の役割を混在させない
- Webhookは即時200、処理は非同期:応答時間を最短に保ち、リトライ嵐を防ぐ
- 状態が必要ならDBに永続化:承認待ちや督促回数などの状態はDBに保持し、Cronで確認する
在庫アラート、承認フロー、月次集計など、業務ごとの起動条件と状態管理の要件に合わせて構成を選びます。
