Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

バージョンアフィニティ

最終更新 Markdown で表示Agent セットアップ

段階的デプロイ では、各リクエストは指定した割合に基づき、どちらのバージョンへもランダムに振り分けられます。そのため、同じユーザーでもリクエストのたびに別バージョンのコンテンツが返ることがあり、バージョンスキュー(version skew)の問題が起きることがあります。

バージョンアフィニティは、安定した識別子に基づいてユーザーをバージョンへ決定的に割り当てます。段階的デプロイのあいだ、ページ読み込みやサブリクエストでも同じバージョンへ一貫して到達します。

仕組み

Worker への受信リクエストに Cloudflare-Workers-Version-Key ヘッダーを設定します。

curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: foo'

ある デプロイ では、バージョンキーが foo のリクエストは、すべて同じ Worker バージョンが処理します。プラットフォームがキーをハッシュし、設定した割合と組み合わせてバージョンを決定的に割り当てます。キーがどのバージョンに対応するかは、自分では選びません。

段階的デプロイを進めると(たとえば 10% から 20%、50% へ)、すでに新バージョンへ割り当てられたキーのユーザーはそのまま残ります。旧バージョンのユーザーは割合の上昇に合わせて新バージョンへ移りますが、ロールバックしない限り元には戻りません。

Cloudflare-Workers-Version-Key ヘッダーは、インターネットから Worker への外部リクエストでも、サービスバインディング を使った Worker 間のサブリクエストでも設定できます。

静的アセット

バージョンアフィニティは、Worker がコンテンツハッシュ付きファイル名(index-a1b2c3d4.js など)の 静的アセット を配信する場合に特に重要です。これは、最近のビルドツールやフレームワークの既定の動作です。

段階的ロールアウト中、アプリケーションのバージョンごとにアセットのファイル名が異なります。

  • バージョン A の HTML は assets/index-a1b2c3d4.js を参照します
  • バージョン B の HTML は assets/index-m3n4o5p6.js を参照します

バージョンアフィニティがないと、ユーザーはバージョン A の HTML を受け取り、ブラウザーが index-a1b2c3d4.js を要求したときに、そのリクエストがバージョン B へ振り分けられることがあります。バージョン B にはそのファイルがないため、404 エラーになり、ページが壊れます。

バージョンキーを選ぶ のいずれかの方法でバージョンアフィニティを設定すると、同一ユーザーからのリクエストはすべて同じバージョンへ振り分けられ、この問題を防げます。

バージョンキーを選ぶ

適切なバージョンキーは、アプリケーションで使える安定した識別子によって変わります。Transform Rule をゾーンに設定すると、アプリケーションコードを変えずにリクエストから値を取り出せます。

認証ありのアプリケーション

Cookie またはヘッダーにユーザー識別子がある場合、これが最もよい選択肢です。各ユーザーはバージョンへ決定的に割り当てられ、セッション、デバイス、再読み込みをまたいでもそのバージョンに留まります。

Expression Editor のテキスト:

http.cookie contains "user_id"

Modify request header で選ぶ操作: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: http.request.cookies["user_id"][0]

セッションがあるアプリケーション

アプリケーションがセッション Cookie を設定する場合は、セッション識別子を使います。セッションのあいだは一貫した振り分けになります。セッションが期限切れになり新しいセッションが作られると、別のバージョンへ割り当てられることがあります。

Expression Editor のテキスト:

http.cookie contains "session_id"

Modify request header で選ぶ操作: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: http.request.cookies["session_id"][0]

リクエストに安定した識別子がない場合、次の 2 つの方法があります。

オプション 1: クライアントの IP アドレスを使う。 最も単純で、アプリケーションの変更は不要です。同じ NAT または VPN の背後にいるユーザーはまとめて扱われ、ネットワークを切り替えるモバイルユーザーはバージョンが変わることがあります。ただし、ほとんどのアプリケーションでは、リクエストごとのランダム振り分けに比べてバージョンの行き来を大きく減らせます。

Expression Editor のテキスト:

true

Modify request header で選ぶ操作: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: ip.src

オプション 2: Worker から長寿命の Cookie を設定する。 最初のリクエスト(ランダムに割り当てられます)で、Worker が安定した識別子を生成して Cookie に設定します。以降のリクエストはその Cookie をバージョンキーとして使います。匿名ユーザーに対して最も一貫した振り分けができます。アプリケーションコードは少し必要です。

export default {
	async fetch(request, env) {
		const response = await handleRequest(request, env);

		// Set a long-lived cookie to use as a version affinity key.
		const COOKIE_NAME = "version-key"; // can be any name
		const cookieHeader = request.headers.get("Cookie") ?? "";
		const hasAffinityCookie = new RegExp(`(?:^|;\\s*)${COOKIE_NAME}=`).test(
			cookieHeader,
		);

		if (!hasAffinityCookie) {
			const id = crypto.randomUUID();
			response.headers.append(
				"Set-Cookie",
				`${COOKIE_NAME}=${id}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=31536000`,
			);
		}

		return response;
	},
};
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const response = await handleRequest(request, env);

    // Set a long-lived cookie to use as a version affinity key.
    const COOKIE_NAME = "version-key"; // can be any name
    const cookieHeader = request.headers.get("Cookie") ?? "";
    const hasAffinityCookie = new RegExp(`(?:^|;\\s*)${COOKIE_NAME}=`).test(cookieHeader);

    if (!hasAffinityCookie) {
      const id = crypto.randomUUID();
      response.headers.append(
        "Set-Cookie",
        `${COOKIE_NAME}=${id}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=31536000`,
      );
    }

    return response;
  },
};

次に、この Cookie をバージョンキーにする Transform Rule を作成します。

Expression Editor のテキスト:

http.cookie contains "version-key"

Modify request header で選ぶ操作: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: http.request.cookies["version-key"][0]

テスト

同じバージョンキーで複数回リクエストし、同じバージョンが処理することを確認すると、バージョンアフィニティが動いているかを検証できます。

# Both requests should return responses from the same version
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: test-user-123'
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: test-user-123'

テスト中は、バージョンメタデータのバインディング を使い、Worker のレスポンスにバージョン ID を含めます。

段階的ロールアウト中は、Worker の分析で 404 レスポンス率の上昇を監視します。特にアセットファイル(.js.css.png)に注意します。Analytics Engine または Logpush でこれらの指標を追跡し、バージョンスキューの問題を早めに見つけます。問題に気づいたら、前のバージョンへ ロールバック できます。

関連リソース

役に立ちましたか?