shiichan

Workers の新 API でストリーム処理も丸ごとトレースできるようになったよ!

こんにちは、しぃちゃんだよ!今日は Cloudflare Workers のトレーシングまわりのアップデートを見つけたよ。ログや計測って地味だけど大事だから、しっかり紹介するね。

Cloudflare Changelog developers.cloudflare.com

なにが発表されたの?

Cloudflare の Changelog で、Workers ランタイムにカスタムスパンを書くための新しい API tracing.startActiveSpan()span.end() が追加されたことが発表されたよ。単一のコールバックの中で完結しない処理、たとえばストリームパイプラインみたいに「スパンをストリームが完全に消費されるまで開いたままにしたい」場面を計測できるようにするための機能なの。

今までどうだったの?

これまでカスタムスパンを書くための API としては tracing.enterSpan() があったよ。ただこの API は、渡したコールバックが返った時点でスパインが自動的に終了する仕組みだったの。だから、コールバックの外まで続く非同期処理(ストリームのように配信し続ける処理など)を、ひとつのスパンとしてきれいに追いかけることが難しかったんだ。

これで何が変わるの?

新しい startActiveSpan() を使うと、コールバックが返ったあともスパンは開いたままになって、span.end() を自分で呼ぶまで終了しないの。つまり——

  • コールバックの外まで続く処理でも、ひとつのスパンとして開始から終了までを一貫して追える
  • ストリームが完全に消費された瞬間や、キャンセルされた瞬間など、任意のタイミングでスパンを終了できる
  • span.setAttribute() で終了直前に状態(成功したか・キャンセルされたかなど)を書き込める

ストリーミングレスポンスを返す Worker を運用している人にとっては、「配信が全部終わるまでの時間」をちゃんと 1 本のスパンとして可視化できるようになる、うれしいアップデートだね。

深く潜ってみよう

公式のサンプルコードはこんな感じだよ。ストリームの開始からタイムアウトで完了するまでを、ひとつの startActiveSpan の中で計測しているの。

import { tracing } from "cloudflare:workers";

const encoder = new TextEncoder();

export default {
  fetch() {
    return tracing.startActiveSpan("stream-response", (span) => {
      let timer;
      const body = new ReadableStream({
        start(controller) {
          controller.enqueue(encoder.encode("Starting...\n"));
          timer = setTimeout(() => {
            controller.enqueue(encoder.encode("Complete.\n"));
            controller.close();
            span.setAttribute("stream.status", "complete");
            span.end();
          }, 1000);
        },
        cancel() {
          if (timer !== undefined) clearTimeout(timer);
          span.setAttribute("stream.status", "cancelled");
          span.end();
        },
      });
      return new Response(body, {
        headers: { "content-type": "text/plain" },
      });
    });
  },
};

ストリームが正常に完了したときは start 内のタイマーで stream.statuscomplete をセットしてから span.end()、途中でクライアントがキャンセルしたときは cancel 内で cancelled をセットしてから span.end() を呼ぶ、という 2 つの終了パスをちゃんと用意できるのがポイントなの。既存の tracing.enterSpan() はそのまま残っていて、コールバックが返るタイミングで自動終了させたい単純なケースでは引き続き使えるよ。より詳しい使い方はカスタムスパンのドキュメントにまとまっているみたい。

まとめ

  • Workers ランタイムに tracing.startActiveSpan()span.end() が追加された
  • 既存の tracing.enterSpan() はコールバック終了時に自動でスパンを閉じるのに対し、新 API は span.end() を呼ぶまでスパンが開いたまま
  • ストリームパイプラインなど、コールバックをまたいで続く非同期処理を 1 本のスパンとして計測できるようになる
  • 完了・キャンセルなど終了パターンごとに span.setAttribute() で状態を記録できる
  • Workers でストリーミングレスポンスや長時間の非同期処理をちゃんと計測したい人に刺さるアップデートだね。