On-demand ISRの機能を試してみた
はじめに
12.1のリリースで、もっともリクエストの多かった機能、On-demand ISRが導入されたらしいので試してみました。
TL;DR
- SSG/ISRで生成した静的ファイルが、どのタイミングで再生成するか試してみたことをまとめた記事です。(
revalidate
で指定した値を過ぎたてアクセスしたり、unstable_revalidate
を実行したり、などいろいろ試してみた結果をまとめてます) - 検証で作ってみたサイトは こちら
- サンプルコードは こちら
On-demand ISRとは
On-demand ISRは、12.1のリリースにてベータ版で入った機能ですが、ISRについてもあらためて。
ISRとは
- まずはドキュメントです。
-
ISRは段階的に静的ファイルを生成する仕組みです。一度生成したファイルを指定した時間経過後にリクエストすると再生成してくれます。
-
getStaticProps
にはrevalidate
というオプションがありますが、ここで指定した時間(秒)を経過後、ページにアクセスすると一度生成したファイルを再生成してくれます。 -
リクエストを受け取った際、stale-while-revalidateの挙動をとり、キャッシュが存在する場合キャッシュに存在する情報を返します。そのあと、バックグラウンドでページを再生成し、キャッシュを更新して、次のリクエストから更新した情報を返します。
-
Vercelのドキュメントにあったこの図の説明がすごくわかりやすかったです。
-
こちらの記事もすごくわかりやすかったです。
- コード例
export async function getStaticProps() {
const currentTime = dayjs().tz();
const createdAt = currentTime.format(formatStyle);
const nextCreatedAt = currentTime.add(revalidate, 's').format(formatStyle);
return {
props: {
createdAt,
nextCreatedAt,
},
revalidate: 60,
};
}
On-demand ISRとは
- まずはドキュメントです。
-
これまでのISRは
revalidate
で指定した時間が経過されるまでは、キャッシュされた情報が返されるので、データを更新してもすぐ反映されないかったのですが、On-demand ISRは指定した時間の経過を待たずに手動でキャッシュのpurgeとページの再生成ができるようになりました。 -
APIルートで、
unstable_revalidate
を実行するとgetStaticProps
を使用する個々のページのキャッシュを再生成してくれます。 -
コード例
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data | string>
) {
try {
await res.unstable_revalidate('/');
return res.json({ revalidated: true });
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).send('Error revalidating');
}
}
試したこと
今回試したことです。
ページ生成時に `getStaticProps` を使い、ページが生成されたタイミングの時刻を取得して表示させるサイトを準備した
- 実装サンプル。
createdAt
がページが生成されたタイミングの時刻 -
revalidate
は60秒で試した
export async function getStaticProps() {
const currentTime = dayjs().tz();
const createdAt = currentTime.format(formatStyle);
const nextCreatedAt = currentTime.add(revalidate, 's').format(formatStyle);
return {
props: {
createdAt,
nextCreatedAt,
},
revalidate: revalidate,
};
}
`revalidate` に指定した時間内でアクセスした場合は、ページの再生成は行われず、キャッシュされたデータが返されることの確認した(サンプルサイトの「いま表示してるHTMLが作られた時刻」で確認できる)
以下、22:47:40 と 22:48:06 にそれぞれアクセスした時の画像ですが、「いま表示してるHTMLが作られた時刻」は同じ時間なので、revalidate
に指定した時間内でアクセスした場合は、ページの再生成は行われず、キャッシュされたデータが返されることを確認できた
-
22:47:40 にアクセスした際の今表示してるHTMLが作られた時刻
-
22:48:06 にアクセスした際の今表示してるHTMLが作られた時刻
-
レスポンスヘッダーが
x-vercel-cache: HIT
になってて、Edgeサーバーのキャッシュからのレスポンスだということがわかります。
The response was served from the edge
`revalidate` に指定した時間経過後アクセスした場合は、いったんキャッシュされたデータが返されますが、裏でページが再生成されてるので、その次アクセスした際にデータが最新になってることの確認した
- 以下、
revalidate
に指定した時間経過後アクセスした際の画像です。stale-while-revalidateの動きをし、まずキャッシュにある情報を返すので、「いま表示してるHTMLが作られた時刻」は「このページにアクセスした時刻」よりも前の時刻になっています。revalidate
で指定した時間経過後にアクセスしてるので、裏でぺーじの再生成が行われており、次回アクセスした際は、以下の画像の「このページにアクセスした時刻」は「いま表示してるHTMLが作られた時刻」になっているはずです。
- 以下、次回アクセスした際の画像です。前回、「このページにアクセスした時刻」は「いま表示してるHTMLが作られた時刻」になっていることがわかります。
-
revalidate
に指定した時間経過後アクセスした際の画像をみると、レスポンスヘッダーがx-vercel-cache: STALE
になっています。これは、Edgeサーバーのキャッシュからのレスポンスを受け取りつつ、バックグラウンドでオリジンサーバーに最新のページを生成します。
The response is stale (served from the edge). A background request to the origin was made to get a fresh version. (Learn more)
`unstable_revalidate` を実行すると、`revalidate` で指定した時間にかかわらずページが再生成されることの確認した
- 以下、23:53:35 に生成されたページを表示してる画像です
- 以下、Call Unstable_revalidate API ボタンをクリックして
res.unstable_revalidate('/');
を叩いた際の画像です
- 以下、
res.unstable_revalidate('/');
を叩いた後、改めてページにアクセスした際の画像です。「いま表示してるHTMLが作られた時刻」は、23:53:35から23:53:53になっていることから、revalidateで指定してる値の60秒を待たずに、res.unstable_revalidate('/');
の実行がトリガーとなり、ページの再生成が行われてるとわかります。
サンプル
以下、試したことで使ったコードとサイトです。
- コード
おわりに
-
個人的にですが、普段は認証が必要なWebアプリケーションを作ることが多く、Full CSRの構成でNext.jsを使ってるので、今回ISRを試しながら、段階的に静的ページを生成する仕組みを学べて勉強になったのがよかったです。
-
今回リリースされたOn-demand ISR以前のISRだと、指定した時間経過後のリクエストをトリガーにrevalidateしてページを再生成していましたが、On-demand ISRの登場で任意のタイミングでキャッシュのpurgeとぺーじの再生成できるようになったので、最新の値の反映がいつ反映されるかわからないというような問題がなくなりそうで良さそうだと思いました。
-
Vercelのキャッシュの仕組み、エッジネットワークに興味湧いたのでドキュメントもっとちゃんと読もうと思いました。
参考
参考にしたリンクたち。すごく勉強になりました。
unstable_revalidate
の実装
Discussion