Web開発
Workers Cache
Workers Cache (blog.cloudflare.com)
要約
Cloudflareは、Workerの前に配置される新しいキャッシュ機能「Workers Cache」を発表しました。これにより、WorkerのCPU時間を節約し、サーバーサイドレンダリングされたアプリケーションのパフォーマンスを大幅に向上させることができます。この機能は、標準的なHTTPキャッシュヘッダーと`stale-while-revalidate`ディレクティブを活用し、開発者がコードでキャッシュを簡単に設定・管理できるようにします。
全文翻訳
Workersは、その前に独自のキャッシュを持つことができるようになりました
2026年7月6日
Dan Lapid
Connor Harwood
17分間
本日、Wranglerの設定1行と、すでに使い慣れているCache-Controlヘッダーで構成される階層型キャッシュであるWorkers Cacheをローンチします。
Workers Cacheが有効になっている場合、Workerへのキャッシュ可能なリクエストはすべてまずCloudflareのキャッシュにヒットします。新鮮なキャッシュされた応答があれば、Cloudflareはそれを直接返します。Workerは実行されず、CPU時間はかかりません。ミスの場合、Workerが実行され、応答がキャッシュ可能であれば、Cloudflareはそれを次回の要求のために保存します。地球上のどこからの次の要求も、キャッシュから直接提供できます。
すべては1つの設定ブロックです:
```json
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2026-05-01",
"cache": {
"enabled": true
}
}
```
その後、HTTPが常に望んでいた方法でキャッシュを制御します。応答にヘッダーを設定します:
```javascript
return new Response(body, {
headers: {
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
"Cache-Tag": "products,product:123",
},
});
```
コンテンツが変更されたら、Workerは独自のキャッシュをパージします:
```javascript
await ctx.cache.purge({ tags: ["product:123"] });
```
それがAPI全体です。設定するゾーンはなく、設定するルールエンジンもなく、プロビジョニングする別のキャッシュもなく、ログインする第2の製品もありません。Workerのコードが設定面であり、キャッシュはWorkerが実行される場所ならどこでもWorkerに従います。カスタムドメイン、workers.dev、サービスバインディングの後ろ、プレビュー、Workers for Platformsテナントなどです。1つのWorker、1つのキャッシュ、一度設定。
それが表面積です。その下には多くのものがあります。ネットワーク全体にわたる階層型キャッシュ、stale-while-revalidateの完全サポート(古い応答がユーザーをブロックしないように)、Varyによるコンテンツネゴシエーション、ctx.propsによるマルチテナントセーフキャッシュキー、タグまたはパスプレフィックスによるプログラムによるパージ、そして最も大きなアンロックになると考えている部分、つまり公開エントリポイントだけでなく、すべてのWorkerエントリポイントの前に配置され、どのエントリポイントがキャッシュされ、どれがキャッシュされないかについてエントリポイントごとの制御が可能なキャッシュです。
最後の部分は、キャッシュをアプリの構造に直接組み込むことができることを意味します。キャッシュステージが好きな場所にスロットインされたエントリポイントのチェーンで、両側のコードによって構成されます。以下でそのすべてを説明します。
Workers Cacheは本日、すべてのプランのすべてのWorkerが利用可能で、Wranglerで有効になっています。
これは、Workersが常に望んでいたキャッシュAPIです。なぜこれほど時間がかかったのか、それによって何が可能になるのか、そして次に何が来るのかを説明します。
サーバーレンダリングされたアプリがキャッシュを必要とする理由
2017年にWorkersを導入したとき、Cloudflareのネットワーク上でコードを実行して、オリジンへのリクエストを変換できるというものでした。Workerはキャッシュとオリジンの前に配置されていました:
これは、ターゲットとしていたユースケースにとって正しいモデルでした。すべてのリクエストにヘッダーを追加したい場合、URLを書き換えたい場合、A/Bスプリットを実行したい場合、またはオリジンに到達する前にトラフィックをフィルタリングしたい場合、Workerをキャッシュとオリジンの前に配置することで、何がキャッシュされ、何がキャッシュされないかを完全に制御できました。顧客はそれを使って信じられないほどのものを作りました。
しかし、世界は変わりました。Workersはオリジンにボルトで固定されるものではなくなり、オリジン自体になり始めました。Astro、TanStack Start、Next.js、Remix、SvelteKitなどのフレームワークは、アプリをWorkerとしてビルドするCloudflareアダプターをすべて出荷しています。それらの後ろにオリジンはありません。Workerがサーバーです。
Workerがオリジンである場合、元のアーキテクチャにはキャッシュできるものがありません。応答が1秒前の応答とバイト単位で同一であっても、すべてのリクエストがコードを実行します。Workersランタイムは非常に高速なので、これは機能します。汗をかくことなく、毎秒数千万のリクエストを日常的に処理します。しかし、「すべてのリクエストをレンダリングするのに十分高速」であっても、すべてのページロードでレイテンシとすべての呼び出しでCPU時間がかかります。そして、サーバーレンダリングされたアプリでは、定義上、すべてのページロードはレンダリングです。
Workers Cacheはアーキテクチャを反転させます。CloudflareのキャッシュがWorkerの前に配置されます:
キャッシュヒットの場合、Workerはまったく実行されません。Cloudflareはキャッシュされた応答を返し、CPU請求はゼロのままです。ミスの場合、Workerは一度実行され、キャッシュを生成し、次のリクエスト(どこからでも)はコードを呼び出さずにキャッシュから提供されます。
これは、Workersでのサーバーサイドレンダリングに欠けていたものです。以前は、2つの不満足な選択肢のいずれかを選択する必要がありました:
ビルド時にすべてを事前レンダリングする(静的サイト生成)。ページロードは高速ですが、変更ごとに完全な再ビルドと再デプロイが必要です。数千ページあるドキュメントサイトの場合、5〜10分です。大規模なeコマースサイトの場合はさらに悪いです。そして、何かを触るたびにビルドが実行されます。
すべてのリクエストで各ページをレンダリングする。最新のコンテンツですが、各ページロードはレンダリングコストを支払い、各訪問者はレイテンシを支払います。
Workers Cacheは3番目の選択肢を提供します。オンデマンドでサーバーレンダリングし、レンダリングされた応答をキャッシュし、選択したTTL(有効期間)で更新します。新しいページの最初の要求はまだレンダリングされます。キャッシュが期限切れになるまでの後続のすべての要求は、ページが静的であったかのように提供されます。キャッシュが期限切れになると、次の要求が再レンダリングをトリガーします。そして、stale-while-revalidateを使用すると、その要求さえ待つ必要はありません。
ビルド時間なしで静的サイトの速度を得て、コストなしでサーバーレンダリングの鮮度を得ます。増分静的再生のようなフレームワーク固有の仕組みはありません。コードの前に、オリジンになるように設計されたコードで、設計どおりに機能するHTTPキャッシュです。
stale-while-revalidateは、それを瞬時に感じさせる部分です
stale-while-revalidateディレクティブは、キャッシュされた応答の有効期限が切れたときに、Cloudflareがバックグラウンドで応答をリフレッシュしながら、古いコピーをすぐに提供することを許可するようにCloudflareに指示します。Cloudflareは今年初めにstale-while-revalidateの完全サポートをリリースしました。これは、「Workerをキャッシュする」を「Workerのサイトが静的であるように感じる」に変えるディレクティブです。
それなしでは、キャッシュエントリの有効期限が切れた後の最初の要求は、Workerがページをゼロからレンダリングするのを待つ必要があります。ユーザーはそのレイテンシを見ます。それを使用すると、有効期限切れ後の最初の要求は古いページをすぐに(Cf-Cache-Status: UPDATINGヘッダー付きで)取得し、Workerはバックグラウンドで実行されてキャッシュを補充します。リフレッシュをトリガーしたユーザーを含むすべてのユーザーが、キャッシュ速度の応答を受け取ります。
実際には、これは次のように表示されます:
```javascript
export default {
async fetch(request) {
const html = await renderPage(request);
return new Response(html, {
headers: {
"Content-Type": "text/html; charset=utf-8",
// 5分間は新鮮として扱い、バックグラウンドリフレッシュ中に最大1時間古いものを提供する
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
},
});
},
};
```
これが理解できるメンタルモデルです:
新鮮なウィンドウ(max-age): Cloudflareはキャッシュされた応答を提供します。Workerは実行されません。
古いウィンドウ(stale-while-revalidate): Cloudflareはキャッシュされた応答を提供します。Workerはバックグラウンドで実行して更新します。ユーザーは待ちません。
両方のウィンドウの外側: CloudflareはWorkerを実行して新鮮な応答を生成し、ユーザーはその1回のレンダリングを待ちます。
ウィンドウを選択します。数分ごとに更新される商品カタログの場合、max-age=300、stale-while-revalidate=3600は、訪問者が基本的に待つことはなく、Workerはコンテンツを新鮮に保つために十分な頻度で実行されることを意味します。ほとんど変更されないブログアーカイブの場合、max-age=86400、stale-while-revalidate=2592000は、Workerがページごとに1日1回実行されることを意味します。
ブランドの新しいページの最初の要求は、完全なレンダリングコストを支払う唯一の要求です。その後、ページは訪問者にとって静的出力のように動作しますが、Workerはページの生成方法を引き続き所有します。
1つのURL、複数の表現: Varyが機能する
実際のアプリは、すべてのクライアントに同じバイトを返すことはめったにありません。同じ商品ページは、ブラウザの場合はHTML、APIクライアントの場合はJSONである可能性があります。同じ画像は、サポートするクライアントの場合はWebPである可能性があります