Waymark: Python向けの永続的ワークフローエンジン

概要

Waymarkは、コードをリプレイするのではなく中間表現にコンパイルすることで、永続的なバックグラウンドワークフローをオーケストレーションするように設計されたライブラリです。RustベースのランタイムとPostgresを主要なバックエンドストアとして活用することで、開発者はサーバーの再起動、クラッシュ、長時間実行される操作に耐えうる標準的な非同期Pythonコードを、複雑なインフラスタックを別途用意することなく記述できます。

コンパイル・ワンス(一度だけコンパイルする)アーキテクチャ

TemporalやVercel Workflowのような「リプレイ」メカニズムに依存する従来の永続的実行エンジンとは異なり、Waymarkはコンパイル・ワンス(一度だけコンパイルする)アプローチを採用しています。リプレイベースのシステムでは、ワークフローコードは各ステップごとに最初から再実行されるため、ユーザーはrandom()やdatetime.now()のような非決定的な関数をワークフローロジック内で避けるなど、厳密に決定論的なコードを書く必要があります。

Waymarkは、Pythonのrun()メソッドの抽象構文木(AST)を中間表現(IR)に解析することでこれを変革しました。このIRは、カスタムの永続的仮想マシンのバイトコードに変換されます。ランタイムがこの仮想マシンの状態をPostgresで追跡するため、ワークフローはリカバリ中に最初から再実行する必要がありません。これにより、開発者はループ、条件分岐、並列ブランチを含む標準的なPythonの制御フローを、決定論に関する制約を減らして使用できるようになります。

基本概念

Waymarkは、分散作業を管理するために2つの主要なプリミティブを区別しています。

  • Actions: これらは、ネットワーク呼び出し、データベースクエリ、あるいは失敗する可能性があり独立した再試行が必要なタスクなど、分散作業単位を表します。Actionsはノードによって実行され、特定の再試行ポリシーやタイムアウトを設定できます。
  • Workflows: これらは永続的な制御フロー層として機能します。Actionsをオーケストレーションしますが、それ自体で重い処理を行うことはありません。並列ファンアウトのためのasyncio.gatherや、プロセス再起動をまたいで持続する永続的な一時停止のためのasyncio.sleepなど、標準的なPythonパターンをサポートしています。

デプロイと使用方法

Waymarkは「インフラストラクチャが軽量」になるように設計されており、Postgresデータベースのみを必要とします。システムにはwaymark-executorからアクセス可能な組み込みのWebアプリケーションが含まれており、ワークフローインスタンス、呼び出しタイムライン、ノード負荷の可視化を提供します。

現在プロジェクトは初期開発段階であり、本番環境での使用は推奨されていませんが、バックグラウンドジョブスタックを簡素化することで、プロダクトマーケットフィットの達成を目指すチームを支援することを目的としています。100ms以下のレイテンシや大規模な並列処理(例:1万件を超える同時実行アクションなど)を必要とする高スケール環境向けではありません。

コミュニティの視点

Waymarkの導入は、その設計のトレードオフに関する議論を巻き起こしました。一部のユーザーは、ワークフローエンジンとアプリケーションコードの密結合の可能性を指摘し、Pythonのバージョンやサードパーティの依存関係が進化するにつれて、長期的な保守性に懸念を表明しています。

また、BazelやNixのようなビルドシステムと比較して、アーキテクチャの転換を強調する声もあります。あるコメント投稿者は次のように述べています。

"NixやBazelで使われている『サンドボックス化された命令型コンポーネントを接続する純粋な調整言語』というアーキテクチャパターンが、分散ワークフローに適用されているのを今初めて見たというのは驚きだ。" — @handle

さらに、一部の開発者はこのライブラリがasyncioに大きく依存していることを指摘し、主に同期コードベースで作業しているチームにとっては敬遠される可能性があると述べています。

Sources