大規模分散システムにおいて、「一時的な障害(Transient Failure)」は避けられない現実です。Netflixは、数千のマイクロサービスを全世界にデプロイする際、Spinnakerというオープンソースの継続的デリバリー(CD)プラットフォームを中核エンジンとして利用してきました。しかし、SpinnakerのClouddriverサービス内の複雑なオーケストレーションロジックと状態管理の限界により、クラウド操作(Cloud Operation)の問題によるデプロイ失敗が約4%に達する課題に直面していました。本記事では、NetflixがどのようにDurable ExecutionプラットフォームであるTemporalを導入してこの問題を根本的に解決し、デプロイ失敗率を 4%から0.0001%へ 劇的に低下させたのか、その過程を探ります。詳細はNetflix Tech Blogの原文をご参照ください。

Spinnaker Clouddriverの弱点
Spinnaker内で、Clouddriverはクラウドインフラの変更(例:サーバーグループの作成/削除)を実行する役割を担っていました。Orca(オーケストレーションエンジン)がClouddriverに作業を要求すると、Clouddriverはそれを下位作業(AtomicOperation)に分解して実行する、複雑な内部プロセスを持っていました。この構造にはいくつかの根本的な問題点がありました。
- 複雑な内部オーケストレーション: Clouddriverは、タスク状態の追跡、リトライ、ロールバック(Sagaパターン)のための独自のロジックを実装する必要がありました。これは、本質的な目標(インフラ変更の実行)とは無関係な「未分化な負荷(Undifferentiated Lifting)」でした。
- インスタンスローカル状態: タスク実行状態は特定のClouddriverインスタンスのメモリに保存されていたため、そのインスタンスがダウンすると、進行中のタスク状態が完全に失われました。
- 密結合(Tight Coupling): Orcaは、Clouddriverの特定の状態ポーリングAPIとエラー処理方法を正確に知っている必要がありました。
この複雑さの中でも、ネットワーク不安定やクラウドプロバイダー障害などの「一時的障害」に対する堅牢な処理は困難であり、最終的に4%のデプロイ失敗率という数字として現れていました。

Temporalによるパラダイムシフト:「失敗が存在しないかのように」コーディング
Temporalは Durable Execution(耐久性実行) を提供するプラットフォームです。開発者は、ビジネスロジックをWorkflow(決定論的な一連のステップ)とActivity(非決定論的な外部作業、例:API呼び出し)として構成するだけで、Temporalサーバーが実行状態を永続的に保存・管理します。ワーカー(Worker)プロセスが停止しても、30日間のスリープ中であっても、Temporalは状態を保持し、別のワーカーで実行を再開できます。
Temporal移行後のアーキテクチャ:
- Orcaは、Clouddriverに直接リクエストする代わりに、Temporalクライアントを使用して
UntypedCloudOperationRunnerWorkflowの実行をリクエストします。 - ClouddriverワーカーがそのWorkflowタスクを受け取り、ペイロードを解釈して適切な
CloudOperationChild Workflowを実行します。 - Child Workflowは、実際のクラウドプロバイダーAPIを呼び出すActivityを実行します。
- Orcaは、Temporalクライアントを通じてWorkflowの完了を非同期に待機します。
この変化により、Clouddriverは複雑なオーケストレーション、状態管理、リトライロジックを自ら実装する必要がなくなりました。すべてはTemporalプラットフォームの責任となったのです。

得られた成果と教訓
主な成果:
- デプロイ失敗率: 4% → 0.0001% (約40,000倍の改善)。
- 結合度の低減: OrcaとClouddriverは、Temporalを媒介として疎結合になりました。
- ステートレス化: Clouddriverインスタンスはステートレスになり、カウトのように扱えるようになり、Chaos Monkeyの適用も可能になりました。
- 可観測性の向上: Temporal UIにより、本番環境で実行中のWorkflowをリアルタイムでデバッグ・監視することが格段に容易になりました。
実践から得られた教訓:
- 不要なChild Workflowは避ける: コードの整理だけのためにChild Workflowを使用すると、デバッグが複雑化する可能性があります。クラスコンポジションを検討してください。
- 単一の引数オブジェクトを使用する: Workflow/Activityメソッドのシグネチャを変更すると、長時間実行されるWorkflowを破壊する可能性があります。すべての引数を保持する単一のシリアライズ可能なクラスを使用するのが安全なパターンです。
- ビジネス失敗とワークフロー失敗を分離する:
WorkflowResultのようなラッパー型を使用して、ビジネスロジックの失敗をワークフロー実行の失敗とは別に伝えることで、より細やかなエラー処理が可能になります。
Netflixはこの成功した移行をきっかけにTemporalの利用が急増し、現在では数百の多様なユースケースでTemporal Cloud(SaaS)を活用しています。複雑性の中で信頼性を確保しなければならないあらゆる分散システム設計者にとって、貴重な洞察を提供する事例です。