決定的ワークフロー実践ガイド:2025年の最新事例3選
CI/CDパイプライン、金融取引、自律飛行システム。現場で使われている決定的ワークフロー(Deterministic Workflow)の最新事例を、ワークフロー図と検証プロセスとともに解説。
「同じコードなのに、本番では動かない」
開発者なら誰もが経験する悪夢。この問題を根本から解決するのが、決定的ワークフロー(Deterministic Workflow) です。
前回の記事「エージェンティック vs デターミニスティック」では、AIワークフローの2つのアプローチを解説しました。今回は、決定的ワークフローが現場でどう活用されているか、最新の事例を3つ紹介します。
決定的ワークフローとは?(復習)
- 再現性:同じ入力なら、必ず同じ出力が保証される
- 監査可能性:全てのステップが記録され、追跡できる
- 予測可能性:失敗しても「どこで」「なぜ」が明確
では、実際の現場ではどう使われているのでしょうか?
事例1:GitHub Actions による CI/CD パイプライン
概要
最も身近な決定的ワークフローの例が、CI/CD(継続的インテグレーション/継続的デリバリー) です。GitHub Actionsを例に、そのワークフロー構造を見てみましょう。
ワークフロー図
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Push │───▶│ Build │───▶│ Test │───▶│ Deploy │
│ (Trigger) │ │ (npm build) │ │ (npm test) │ │ (Cloudflare) │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
▲ │ │ │
│ ▼ ▼ ▼
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ Cache │ │ Report │ │ Notify │
│ │ (node_modules│ │ (Coverage) │ │ (Slack) │
│ └──────────────┘ └──────────────┘ └──────────────┘
│
Rollback(失敗時は自動ロールバック)
決定的にするためのベストプラクティス
- アクションのバージョン固定:
actions/checkout@v4ではなくactions/checkout@v4.1.1のようにパッチバージョンまで指定 - 依存関係のキャッシュ:
node_modulesをキャッシュし、毎回同じ依存関係を使用 - イミュータブル・インフラストラクチャ: Dockerイメージは一度ビルドしたら変更しない
検証プロセス
# .github/workflows/ci.yml(抜粋)
jobs:
build:
runs-on: ubuntu-22.04 # OSバージョンを固定
steps:
- uses: actions/checkout@v4.1.1 # バージョン固定
- uses: actions/setup-node@v4
with:
node-version: '20.10.0' # Node.jsバージョンを固定
cache: 'npm'
- run: npm ci # npm install ではなく ci で再現性を保証
- run: npm test
- run: npm run build
ポイント:
npm installではなくnpm ciを使うことで、package-lock.jsonに記載された完全に同じバージョンの依存関係がインストールされます。
事例2:Temporal による金融取引ワークフロー
概要
金融業界では「1円でも間違えてはいけない」ため、決定的ワークフローが必須です。Temporal は、Uber、Netflix、Stripe などが採用するワークフローエンジンで、障害が起きても確実に処理を完了させることを保証します。
ワークフロー図
┌─────────────────────────────────────────────────────────────────┐
│ 送金ワークフロー │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 送金依頼 │───▶│ 残高確認 │───▶│ 引落し │───▶│ 入金 │ │
│ │ (Start) │ │ (Check) │ │ (Debit) │ │ (Credit) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Event History(不変の履歴) │ │
│ │ [WorkflowStarted] → [ActivityCompleted] → [ActivityCompleted] → ... │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 💡 障害発生時:履歴を再生(Replay)して、同じ状態に復元 │
│ │
└─────────────────────────────────────────────────────────────────┘
なぜ決定的なのか?
Temporalの核心は 「履歴の再生(Replay)」 です。
- ワークフローの各ステップは イベント履歴 として永続化される
- 障害が発生しても、履歴を最初から再生することで 全く同じ状態 に復元できる
- 「Exactly-once(厳密に1回だけ実行)」を保証
検証プロセス
// Temporal ワークフロー例(Go言語)
func TransferWorkflow(ctx workflow.Context, fromAccount, toAccount string, amount int) error {
// ❌ 非決定的(NG): time.Now() は再生時に値が変わる
// timestamp := time.Now()
// ✅ 決定的(OK): Temporal の時刻関数を使う
timestamp := workflow.Now(ctx)
// Activity(外部処理)を呼び出し
err := workflow.ExecuteActivity(ctx, DebitActivity, fromAccount, amount).Get(ctx, nil)
if err != nil {
return err // 失敗したらここで停止(自動リトライ設定可能)
}
err = workflow.ExecuteActivity(ctx, CreditActivity, toAccount, amount).Get(ctx, nil)
return err
}
注意: ワークフロー内で
time.Now()やrand.Int()を直接使うと、再生時に値が変わり非決定的になります。Temporalでは専用の関数(workflow.Now()など)を使う必要があります。
事例3:自律飛行システムの決定的コンパイル
概要
ドローンや航空機の自律飛行システムでは、ソフトウェアのバグ=人命に関わるため、最高レベルの決定的ワークフローが求められます。Embention社(自律飛行システム開発)の事例を見てみましょう。
ワークフロー図
┌───────────────────────────────────────────────────────────────────────┐
│ 決定的コンパイル・パイプライン │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ [開発者のコード] │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 隔離された │ ← 外部ネットワークから完全に遮断 │
│ │ CIサーバー │ ← 同一のOSイメージ、ツールチェーンを使用 │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────┐│
│ │ コンパイル → バイナリ生成 → ハッシュ検証 → 署名 ││
│ └──────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ バイナリA │ == │ バイナリB │ == │ バイナリC │ ← 3回ビルド│
│ │ (Hash: abc) │ │ (Hash: abc) │ │ (Hash: abc) │ して比較 │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ 【一致しなければデプロイ禁止】 │
│ │
└───────────────────────────────────────────────────────────────────────┘
決定的にするための技術
- 隔離されたCI環境: ビルドサーバーは外部ネットワークから遮断され、同一環境で繰り返しビルド
- タイムスタンプの排除:
SOURCE_DATE_EPOCH環境変数を設定し、ビルド時刻をバイナリに埋め込まない - 複数回ビルドしてハッシュ比較: 同じソースから複数回ビルドし、生成されるバイナリのハッシュが一致することを検証
検証プロセス
# 決定的ビルドの検証スクリプト例
export SOURCE_DATE_EPOCH=0 # タイムスタンプを固定
# 3回ビルドしてハッシュを比較
for i in 1 2 3; do
make clean && make
sha256sum build/firmware.bin >> hashes.txt
done
# 全てのハッシュが一致するか確認
if [ $(sort -u hashes.txt | wc -l) -eq 1 ]; then
echo "✅ 決定的ビルド成功:全ハッシュ一致"
else
echo "❌ 非決定的ビルド検出:デプロイ禁止"
exit 1
fi
なぜここまでやるのか?: 自律飛行システムでは、テスト環境で動いたバイナリと本番環境のバイナリが 1ビットでも違う と、予測不能な動作を起こす可能性があります。決定的ビルドは「テストしたものと全く同じもの」が本番で動くことを保証します。
まとめ:決定的ワークフローを選ぶべきケース
| ケース | なぜ決定的が必要か | 代表的ツール |
|---|---|---|
| CI/CD | 「動いていたコードが動かない」を防ぐ | GitHub Actions, GitLab CI |
| 金融取引 | 1円も間違えられない、監査対応 | Temporal, Cadence |
| 航空・医療 | 人命に関わる、規制遵守 | 隔離CIサーバー、決定的コンパイラ |
出典・参考資料
公式ドキュメント
- GitHub Actions Documentation: ワークフロー設定の公式リファレンス
- Temporal.io Documentation: Temporalの決定的実行モデルの詳細
技術記事・事例
- Embention: Deterministic Compilation in Autonomous Flight: 自律飛行システムにおける決定的ビルドの事例(2025年)
- Docker: Reproducible Builds: SOURCE_DATE_EPOCH を使った再現可能ビルド
企業導入事例
- Netflix: Temporalを使ったメディアエンコーディング・パイプライン
- Stripe: 決済処理における決定的ワークフロー
- Coinbase: 全トランザクションをTemporalで管理