分散システムの修正を止めて、Restateで暮らす始め方
想像してみてください:決済処理のマイクロサービスを書いています。処理途中でネットワークが一瞬不安定になり、データベースがタイムアウトしたり、コンテナが単に再起動したりします。トランザクションはどうなるでしょうか?古典的なシナリオでは、手動でリトライロジックを実装し、冪等性を追跡し、メッセージキューを設定し、おそらく複雑なサーガを導入する必要があります。それは痛苦的で、時間がかかり、コードをエラーハンドラの迷路に変えてしまいます。
最近、Restateというプロジェクトを発見しました。この問題はインフラレベルで取り組むプロジェクトです。開発者はこれを「Durable Execution」と呼んでいます—フォールトトレラントなコード実行です。あなたのコードが不滅になるのがアイデアです:プロセスがクラッシュしても、Restateは中断した場所から再開し、すべての変数と状態を保持します。
そもそも这是什么
Restateは、プロキシサーバーとして機能し、サービスの調整を行うRustバイナリです。状態管理与び呼び出しのすべての汚い仕事を引き受けます。TypeScript、Python、またはGoで通常のコードを書き、SDKを使用し、突然関数が信頼できるワークフローに変わります。
Temporalのような重量級ソリューションとの主な違いは、Restateの方がはるかに始めやすいことです。巨大なデータベースや複雑なワーカーのセットアップは不要です。単一のバイナリまたはDockerコンテナを実行するだけで、すぐに作業を開始できます。
Restateは実際にはどのように役立つか
このプロジェクトには、あなたの生活を本当に簡素化するいくつかの素晴らしい概念が含まれています。
Guaranteed execution
Restateを通じて関数を呼び出した場合、最後まで実行されます。終わり。サーバーがクラッシュしても、Restateはそれが戻ってくるまで待ち、最後の成功したステップから実行を再開します。メールがユーザーに2回送信されたか、お金が2回請求されたかを心配する必要がなくなりました。
Smart timers and promises
通常、分散システムで遅延を実装するのは探索です。遅延キューにメッセージを配置するか、cronジョブを設定する必要があります。Restateでは、単にawait sleep(Duration::from_secs(86400))と書くだけです。スレッドは無意味にブロックされません:サービスは完全にシャットダウンでき、3日後Restateはそれを「起動」して実行を再開します。
State right in the code
Restateを使用すると、特定のエンティティ(たとえばユーザーID)にバインドされたK/V状態を保存できます。通常のオブジェクト操作のように見えますが、背後でRestateはデータが一貫しており、リクエストと一緒に常に利用可能であることを保証します。これは、関数が通常メモリを持たないサーバーレスアーキテクチャで特に便利です。
コードではどのように見えるか
たとえば、メールアドレスの確認を含むユーザー登録プロセスを実装する必要があるとします。Restate SDKを使用したTypeScriptでは、次のように見えます:
import * as restate from "@restatedev/restate-sdk";
const userService = restate.service({
name: "users",
handlers: {
register: async (ctx: restate.Context, user: { id: string, email: string }) => {
// Сохраняем состояние
ctx.set("status", "pending");
// Отправляем письмо (Restate гарантирует, что это случится 1 раз)
await ctx.run(() => sendWelcomeEmail(user.email));
// Ждем подтверждения или таймаута в 24 часа
const confirmed = await ctx.awakeable<boolean>("email-confirmed");
if (confirmed) {
ctx.set("status", "active");
}
}
}
});
ここでは、await ctx.invoke(sendEmail, { to: email, template: "welcome" })が副作用(メール送信)が正常に実行され、結果がキャッシュされることを保証します。送信後に関数がクラッシュした場合、再起動時にRestateは単にこのステップをスキップし、既に完了していることを認識しています。
技術的な側面
このプロジェクトはRustで書かれており、優れたパフォーマンスを提供します。アーキテクチャ的に、Restateはインボーカーとして機能します。HTTP/gRPCで受信リクエストを受け取り、ログに書き込み、ハンドラを呼び出します。
興味深いことに、Restateは実行を「中断」できます。コードが外部APIまたはタイマーからの応答を待っている場合、Restateはリソースを解放します。イベントが発生すると、実行コンテキストを復元します。これにより、控えめなハードウェアで数千の長時間実行プロセスを実行できます。
試してみるべき人
Restateは、次のようなプロジェクトのギャップを完璧に埋めます:
- マイクロサービス間の呼び出しチェーンが多い。
- 複雑なアクションのチェーン(サーガ、ワークフロー)を構築する必要がある。
- LLM応答を長時間待ち、会話コンテキストを保持する必要があるAIエージェントを使用している。
- 遅延実行タスクがある(2時間後にカート放棄のリマインダーなど)。
このプロジェクトは積極的に開発されており、GitHubでほぼ4,000個のスターを獲得しています。TypeScript/JavaScript、Java/Kotlin、Python、Go、Rust用のSDKが利用可能です。
もちろん、大きな銀行のプロダクションに慌てて新しいインフラコンポーネントを導入するべきではありません—まずローカルで試す必要があります。しかし、スタートアップや既存プロジェクトの新機能には、数週間の開発を節約できる可能性があります。
literally数分で試すことができます:
brew install restatedev/tap/restate-server
restate-server
これでフォールトトレラントなアプリケーションを実行するためのローカル環境ができました。これが現時点でのDurable Executionの世界への最低のエントリーバソコンおそらくでしょう。
関連プロジェクト