💬

ベータ版Vercel Cron Jobsを試す

2023/02/24に公開約3,100字

ここ最近で、Vercel Cronのベータ版がリリースされました。サーバレス関数の定期実行がとても楽になりますね。
今回はVercel Cronジョブの検証を行なっていきます。定期実行がわかりやすいよう、LINE Messageing APIを使用していきます(設定方法は割愛します)。
https://vercel.com/docs/cron-jobs

セットアップ

Next.jsプロジェクトからVercelデプロイまでを説明します。

Next.jsプロジェクト作成

まずは雛形をさくせいします。TypeScriptを使用します。

npx create-next-app vercel-cron-app

次にcronが起動したのがわかるよう、テスト用で作成したLINEチャネルで通知が来るか検証します。

api/cron.ts
import axios from 'axios'
import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
  message: string
}

if (!process.env.LINE_API_TOKEN) {
  throw new Error('トークンがありません')
}

if (!process.env.LINE_USER_ID) {
  throw new Error('ユーザーIDがありません')
}

const lineClient = axios.create(
  {
    baseURL: 'https://api.line.me',
    headers: {
      Authorization: `Bearer ${process.env.LINE_API_TOKEN}`
    }
  }
)

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  await lineClient.post('v2/bot/message/push', {
    to: process.env.LINE_USER_ID,
    messages: [
      {
        type: 'text',
        text: 'こんにちは。\ncronが起動しました。'
      }
    ]
  })
  
  res.status(200).json({ message: 'DONE' })
}

cron設定ファイル

プロジェクトルート上に、cronを使用するためのvercel.jsonを追加します。
scheduleではUTCを考慮し、9時間時差で設定を行います。今回は日本時間で朝6時に起動するように設定します。

vercel.json
{
  "crons": [
    {
      "path": "/api/cron",
      "schedule": "0 21 * * *"
    }
  ]
}

以下、Vercel公式から拝借したcron表現図になります。

Cron Expressions
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (0 is Sunday, 6 is Saturday)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *

デプロイ

Vercelへデプロイします。
ここではVercel CLIを使用していきます。

vercel deploy --prod

cron結果

動作していたのですが、なぜか50分ほどの差がありました。
原因はわかりません(分刻みの差まで考慮しないといけないわけじゃないよね?サーバーの負荷とかかな)。

ダイナミックルート

/api/post/[id].tsxみたいな動的にパラメータを組み込むダイナミックルートにも対応している様子です。
https://vercel.com/docs/cron-jobs#are-dynamic-routes-supported

セキュリティ面

誰でもcron関数が使用できたら良くないのでセキュリティはどうなっているのか気になります。
結論、現在組み込みでcronジョブを保護する方法はないそうです。その代わりにクエリ文字列を使用して関数とキーを共有する方法が書かれています。

vercel.json
{
  "crons": [
    {
      "path": "/api/cron?secureKey=xxx",
      "schedule": "0 21 * * *"
    }
  ]
}
api/cron.ts
...
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  if (req.query.secureKey !== 'xxx') {
    res.status(404).end()
    return
  }
  ...
}

Hobbyプランの制限

実は毎分設定しようとすると以下のようなエラー文が出ます。
これ、Hobbyプランだったら1日の使用に限りがあるっていう内容なんですね。10分毎にしようとしたら怒られました。

Hobby accounts are limited to daily cron jobs. This cron expression (*/10 * * * *) would run more than once per day. Upgrade to pro to unlock all Cron Jobs features on Vercel.

解消法はProプラン以上にしなければいけない様子です。
https://vercel.com/docs/cron-jobs#limits

最後に

毎日1回使用したい場合にはHobbyプランでも問題なさそうです。検証結果で時間がズレた理由は分かりません、誰か教えていただけると幸いです。
1日の中で複数回しようしたければProプラン以上で進めるしかなさそうです。

プロジェクト仕様で、適材適所で使用できればと考えています。

Discussion

ログインするとコメントできます