⚙️

Fastly Compute を便利に使う Tips (2) Timeout を使った実行時間の管理

2023/12/24に公開

この記事は Fastly Compute (旧 Compute@Edge) 一人アドベントカレンダー 23 日目の記事です。

前回に引き続き本稿でも Yamagoya 2023 でのパネルディスカッションの内容を引用しますが、こちらはイベントの中では答えが示されなかった内容について後日少し調べを進めた内容について書いてみたいと思います。

パネルディスカッション後編の最後のテーマで、「Edge Computingのタイムアウト」をサポートしてほしいという議題が上がりました。具体的には、Fastly Compute から origin に対して HTTP リクエストを作成した際に、Origin 側で何らかの理由で処理に時間がかかりすぎた場合には処理の途中でリクエストをキャンセルできるようサポートを追加してほしい、という内容でした。Fastly Compute では処理が実行された時間(vCPUやメモリの使用時間)が費用発生に直結する要素となっているため[1]、処理時間を制御することで不必要な費用の発生を防ぎたい、というのがモチベーションの一つというお話でした。

その場では主に SDK の API レベルでキャンセルができるようにしたいという方向で議論が進んでいましたが、利用している SDK によっては言語レベルでの工夫でキャンセルと同様のことができたり、β版での提供となっている Dynamic backend を使う場合にはこの点柔軟に制御が効かせられることなどがその後の調べでわかってきたため、以下に内容をまとめたいと思います。

実装方法 1. Dynamic Backend で各種タイムアウトを動的に設定する

今回のアドベントカレンダーにて「Fastly Compute HTTP リクエストの作成 (1) Static/Dynamic バックエンド」の回で紹介した方法です。同じ内容になりますが、Rust での実装例を再掲します。

use fastly::{Error, Request, Response,backend::BackendBuilder};
use std::time::Duration;

#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
  let backend = Backend::builder("my_backend", "www.fastly.com")
    .override_host("www.fastly.com")
    .connect_timeout(Duration::from_secs(20))
    .first_byte_timeout(Duration::from_secs(20))
    .between_bytes_timeout(Duration::from_secs(20))
    .enable_ssl()
    .finish()?;
  Ok(req.send(backend)?)
}

なお、上記は fiddle では動作しないことに注意してください (Dynamic backendはサポートされているのですが、残念ながら Timeout は2023年12月現在未サポートの状態)。

実装方法 2. 言語固有の機能を活用する(例:JavaScript の setTimeout())

Developer サイトの Example に実装例があります。JavaScript と Go の実装例が紹介されており、例えば JavaScript の場合の実装例はどちらも再掲します。

addEventListener("fetch", event => {
  event.respondWith(app(event));
});

async function app(event) {
  const backendResponse = fetch(event.request, {backend: "origin_0"});
  const rejectAfter150ms = new Promise((_, reject) => {
    setTimeout(reject, 150);
  });
  const response = Promise.race([backendResponse, rejectAfter150ms]).catch(() => {
    return new Response('backendResponse took more than 150ms to receive so we ignored it');
  });
  return response;
}

公式の実装例では他に Go の context.WithTimeout を利用した例が紹介されていますが、他にも goroutine を利用したタイマー制御なども考えられるかもしれません(未検証)。

実装方法 3. Static Backend(Host) の設定を変更する

こちらは動的というよりは管理画面から Service の設定自体を変更するため細かい粒度でタイムアウト値を変更したい場合には不向きですが、Service 全体で適用される形でも問題なければ、Static Backend(Host) の Connection timeoutFirst byte timeoutBetween bytes timeout といった設定を変更することで origin 接続のタイムアウト時間を Service 全体で変更することも可能です。

まとめ

本稿では Timeout を有効に利用して実行時間を効果的に管理する実装についていくつか方法案を検討しました。明日は Fastly の公式サイトや GitHub 組織で公開されているソースコードやトレーニング等のコンテンツの中で、 Compute 用に覚えておくと便利そうな内容を紹介します。

脚注
  1. 費用の計算について詳しく確認したい方は、アドベントカレンダーの4日目のこちらの記事を参照してください ↩︎

Discussion