私たちが過去数年間行ってきたエンジニアリング作業の多くは、お客様の CPU 使用量とウォールクロックタイム (経過時間) の削減を支援することに重きを置いてきました。数か月前、私たちは、これを反映するために料金モデルを刷新し、デュレーションメーターを廃止して、リクエストと vCPU 消費に厳格にフォーカスする方針をとりました。この新しいモデルによってお客様により優れたコントロールが提供されるため、お客様はより効率的なコードを記述して、支出を直接的に削減できるようになります。
この効率化への取り組みは、最近の顧客主導のエンジニアリング作業にも反映されており、特に演算負荷の高いエージェント型ワークフローでは、サービスがウォールクロックの限界に達するため、より長く実行されるバックエンドリクエストのサポートが必要とされています。
大規模言語モデル (LLM) へのリクエストのプロキシには時間がかかるため、私たちは、利用可能なエッジリソースを拘束することなく、開発者がこれらのレスポンスを待機できる方法を提供したいと考えました。結果として、このニーズに対応することで、より広範なプラットフォームの改善へと進化しました。これは今後も拡大を続けると思われます。その改善とは、新しいリクエストハンドオフ機能の追加です。この機能は Fastly Rust SDK バージョン 0.13.0 でご利用いただけます。
Wasm のゲスト制限と長期間実行されるリクエストの管理
Compute は通常、Wasm ゲストに対して2分間のウォールクロックタイムアウトを強制します。この制限は、リソースを保護し、リクエストの健全な処理を確保するための意図的なものです。また、この設計は、実行中の Wasm ゲストと受信リクエストの 1:1 のマッピングを維持する、大部分のマイクロサービスやエッジロジックにおいても完全に機能します。
ただし、このアーキテクチャは、低速または無応答のバックエンドを待つ際に問題となる場合があります。これは、オリジンでの高負荷により実行中のすべてのリクエストが低速化していることや、レスポンスを生成するために負荷の高い演算を完了する必要があることが原因である可能性があります。時には、オリジンのコントロール内でさえない場合もあります。たとえば、長期間実行されている POST リクエストで、大量のアップロードやモバイルクライアントからのバイトの遅延によりボディバイトを書き込むのに時間がかかることがあります。
(注:Wasm ゲストとは、Wasm ホスト内で実行されるコンパイル済みの Wasm モジュールのことです。Wasm ゲストは厳格なサンドボックス内で実行されるため、ホストは、基盤となるシステムが侵害されるのを防ぎながら、信頼性の低いコードを安全に実行できるようになります。)
ソリューション:PendingRequest::send_to_client
これらの長期間実行されているバックエンドリクエストをより良くサポートし、RPS のスループットを向上させるために、私たちは新たに PendingRequest::send_to_client 機能を導入しました。この新機能により、非同期リクエストをオリジンに送ることができ、ダイレクトパスや hit-for-pass のリクエストであれば、最終的なレスポンスが分かる前であっても、実行中にゲストからホストへ渡すことができます。その後、プラットフォームに対し、最終的に解決した時点でダウンストリームのクライアントにレスポンスを返送するように指示できます。リクエストはバックグラウンドで実行され続けるため、Wasm ゲストは早期に終了し、今後のリクエストのためにリソースを解放できます。このアプローチは、RPS のスループットを大幅に向上させ、Compute サービスが長期間実行中のリクエストの完了を待つことで利用可能な Compute インスタンスを使い果たすのを防ぐことができます。
Hello World の例:
use fastly::{Error, Request};
fn main() -> Result<(), Error> {
// 1. Receive the incoming downstream request from the client:
let req = Request::from_client();
// 2. Dispatch the direct pass request asynchronously to your slow backend:
let pending_req = req.with_pass(true).send_async("my_slow_origin_backend")?;
// 3. Hand off the unresolved, in-flight request directly to the host daemon:
pending_req.send_to_client()?;
// 4. Terminate the guest cleanly.
// The host daemon takes over, monitoring the request and piping the eventual
// response back downstream completely independently.
Ok(())
}主要なユースケース
負荷の高い演算を伴う AI ゲートウェイと長期間実行される LLM ループ:今年の始めに私たちは、開発者が安全で低レイテンシの AI エージェントループを Fastly Compute 上で直接構築する方法について検討しました。エージェント型ワークフローでは、エッジサービスが推論、ツールコール、および外部モデルプロンプトの複数の反復を調整することがよくあります。私たちのランタイムはこれらの自律エージェントを実行するために非常に安全な環境を提供しますが、負荷の高いテキスト生成タスクやアップストリームの LLM プロバイダーの複雑な処理により、ヘッダーが生成される前に処理時間が大幅に長くなる可能性があります。これに対し、Rust SDK の新しい API を使用してそれらの接続パターンを再利用すれば、Fastly Compute をインテリジェントでスループットの高い AI ゲートウェイとして使用できるようになります。これによりエッジアプリケーションは、動的バックエンドを介してリクエストを認可し、クライアントの権限を評価し、またはセマンティックキャッシュレイヤーを注入した上で、負荷の高い LLM コールを非同期で実行できます。
オリジンシールド最適化:ほとんどのアーキテクチャは初期リクエストをエッジ POP にルーティングし、そこからシールド POP へプロキシして、そこで重い操作が行われます。通常はエッジ POP が最終レスポンスを変更することは少なく、代わりにシールド POP のレスポンスをそのまま通過させます。リクエストハンドオフを保留すると、エッジ POP はシールドリクエストを非同期で実行してハンドオフし、ローカルのゲストフットプリントを即座に終了できるため、最も近いエッジ POP での総ウォールクロックタイムを大幅に短縮できます。

図1:このグラフは、NYC に対してシールドを行い、ブリスベン (BNE) で安定したトラフィックを受信しながらシールドリクエストをハンドオフする Compute サービスを示しています。ハンドオフ機能を使用すると、BNE でのウォールクロックタイムはほとんどなくなります。
長期間続くアップロード:お客様のサービスがエッジで低帯域幅クライアントからコンテンツを受け取っている場合、この機能を使用すれば、プラットフォームが Wasm ゲストの実行とは独立してアップロードを継続できるようになり、ゲストのウォールクロックタイムアウトを回避できます。
ヘッダーの変更とエラー処理
この新しい機能には、最終レスポンスのヘッダーを変更する機能も含まれます。実際のハンドオフを行う前に、特定のヘッダーの削除や挿入の変更をキューに追加できます。これにより、「このヘッダー名を削除する」や「このヘッダーに値 X を挿入する」といった変更を指定でき、レスポンスが到着したときに実行されます。
use fastly::{Error, Request};
use fastly::http::request::PendingResponseKind;
fn main() -> Result<(), Error> {
// 1. Receive the incoming downstream request from the client:
let req = Request::from_client();
// 2. Dispatch the direct pass request asynchronously to your slow backend:
let mut pending = req.with_pass(true).send_async("my_slow_origin_backend")?;
// 3.1 Remove the `Server` header added by the origin's application server:
pending.remove_response_header("Server", PendingResponseKind::Response);
// 3.2 Insert the current service version for debugging:
pending.set_response_header(
"X-Service-Version",
fastly::compute_runtime::service_version().to_string(),
PendingResponseKind::Any
);
// 4. Hand off the unresolved, in-flight request directly to the host daemon:
pending.send_to_client()?;
// 5. Terminate the guest cleanly.
// The host daemon takes over, monitoring the request and piping the eventual
// response back downstream completely independently.
Ok(())
}上記の例における PendingResponseKind タイプの使用に注目してください。これによりサービスは、ヘッダーの変更をオリジンレスポンス (PendingResponseKind::Response)、処理中のリクエストが失敗した際に生成されるシンセティックエラーレスポンス (PendingResponseKind::Error)、またはその両方 (PendingResponseKind::Any) に適用するかどうかをコントロールできます。実行中のリクエストが失敗した場合は、適切な 5XX レスポンスが生成され、クライアントに返送されます。通常、これは以下のいずれかになります。
504 Gateway Timeout:オリジンへの接続がタイムアウトした場合、またはバックエンドのファーストバイトタイムアウトに達した場合に自動的に返されます。
502 Bad Gateway:オリジンが不完全または誤った形式のレスポンスボディを返した場合、バックエンドに無効な TLS 証明書がある場合、またはそれ以外で正常に機能/応答していない場合に返されます。
Fastly コントロールパネルのオブザーバビリティダッシュボードにある「バックエンドリクエストおよびエラー」グラフを使用すると、502 および 504 レスポンスの原因となっているバックエンドエラーの種類を確認できます。詳細については、「バックエンドリクエストエラー」をご覧ください。
今すぐ開始
本番環境にサービスをデプロイするのを待たずに、この新しい機能がどのようなメリットをもたらすのかを確認できます。これは、ローカルテスト環境である Viceroy の最新リリースで完全にサポートされています。長期間実行されるバックエンドタイムアウトのエミュレート、Request::send_async/PendingRequest::send_to_client を使用したコードのリファクタリング、キューに入ったヘッダー操作のデバッグを、ローカルの開発ターミナルから直接行うことができます。ハンドオフ機能は現在 Rust SDK (v0.13.0) 限定ですが、その他の公式 SDK にも拡張される予定です。詳細についてはドキュメントをご確認ください。また、フォーラムでお客様が構築中の内容をぜひお知らせください。

