🕒

Cron TriggersでCloudflare Pagesを定期的にビルドする

2023/11/21に公開

経由

自分が管理しているサイトは更新頻度が少なく、総データも少ないため、ビルド時にデータを取得するJamstackを採用しています。
データはHeadless CMS(microCMS)と外部APIを利用しています。

Headless CMSはデータの更新時にWebhookによる通知ができます。これによってビルドサーバーに「投稿データを更新したから、再度ビルドしてデータを取得してね」と伝えることができます。

fetch-data-from-headless-cms

ただ、Webhookによる通知に対応していない外部のAPIを利用する場合、データが更新されてもビルドサーバーはその更新を知ることがないため、ビルドが実行されません。

fetch-data-from-external-api

対応策としては色々あるのですが、今回は多くて1日1回と更新頻度も多くないため、定期的にビルドする方針にしました。

余談: クライアントサイドFetch

他の対応策として「ページ表示時にクライアントサイドでFetchする」という案も考えていたのですが、今回利用した外部APIがCORS対策されているので、外部APIを叩くためのServerless Functionsを立てる必要がありました。
その方が最新の情報を取得できますが、基本的に静的にパッと表示されるサイトにしたかったのと、クライアントサイドFetchのためにLoading等でジャカジャカした表示を見せたくないので見送りました。

Webhookを定期的に叩いてPagesを定期的にビルドする

標準の機能でPagesを定期的にビルドするオプションを探してみましたが、ありませんでした。ただ、前述の通り、PagesはWebhookによる通知で再度ビルドを実行できます。

Cloudflare Workersを定期実行するためのCron Triggersがあります。これを利用して定期的にWebhookで通知を送ります。

https://developers.cloudflare.com/workers/configuration/cron-triggers/

Webhookのエンドポイントを控えておく

先にWebhookのエンドポイントを控えておきます。
Cloudflareの管理画面からPagesのプロジェクトを選択してSettings>Builds & deployments>Deploy hooksを選択します。

Add deploy hookで適当な名前をつけてHookを作成します。

ここで取得したデプロイ用のHookは外部に公開しないようにシークレットキーと同等の取り扱いをします。

Cron Triggerの作成

雛形を作成します。 執筆時点ではwrangler initはサポートされなくなったのでnpm create cloudflareで雛形を作成します。

実行すると対話方式で聞かれるので回答内容はWhat type of application do you want to create?にてScheduled Worker (Cron Trigger)を選択します。

npm create cloudflare 

作成された雛形を開いて実装します。1日1回実行して欲しいので今回は毎日午前12時に実行するようにしました。開発段階では1時間に1回など、頻度を狭めておくと確認がしやすいです。

wrangler.toml
[vars]
WEBHOOK_URL = '<YOUR_WEBHOOK_URL>'

[triggers]
# run At 12:00 AM every day
crons = ["0 0 * * *"]
src/index.ts
export interface Env {
  WEBHOOK_URL: string;
}

export default {
  async scheduled(
    event: ScheduledEvent,
    env: Env,
    ctx: ExecutionContext,
  ): Promise<void> {
    try {
      const res = await fetch(env.WEBHOOK_URL, {
        method: "POST",
      });
      const wasSuccessful = res.ok ? "success" : "fail";
      console.log(`trigger fired at ${event.cron}: ${wasSuccessful}`);
    } catch (error) {
      if (error instanceof Error) {
        console.error(`trigger fired at ${event.cron}: ${error.message}`);
      } else {
        console.error(`trigger failed at ${event.cron}`);
      }
    }
  },
};

デプロイします。

$ wrangler deploy

Cron TriggersによるWebhook通知が成功すると、Pagesの管理画面のDeploymentsにて定期的にビルドされているのが確認できます。

デプロイ頻度があまりに多すぎるとPagesフリープランの上限に引っかかるので適当に設定しましょう。

参考

https://www.codemzy.com/blog/scheduling-builds-cloudflare

Discussion