Skip to content

Cron jobs

A cron job calls a path on your production site on a schedule: send the daily digest, clear expired sessions, sync with another API. Open Project › Cron jobs › New cron job, give it a name and a path like /api/cron/digest, and pick a schedule.

Schedules are standard cron expressions: minute, hour, day of month, month, day of week, read in the job’s time zone (your browser’s, unless you pick another; UTC is in the list too). 0 9 * * * in Europe/Berlin stays at 09:00 Berlin time through daylight saving changes. A time skipped when clocks spring forward runs right after the jump; a time that happens twice when clocks fall back runs once. The dashboard offers common schedules and shows the next three runs as you type.

ExpressionRuns
*/15 * * * *Every 15 minutes
0 * * * *Every hour, on the hour
0 9 * * *Every day at 09:00
30 8 * * 1-5Weekdays at 08:30
0 0 1 * *The first of every month

@hourly, @daily, @weekly and @monthly work too.

Your endpoint#

HostEdge sends a GET (or POST with a small JSON body, if you choose it) to your production URL. A response from 200 to 299 counts as success. Redirects are not followed, so point the job at the final path. Calls give up after 30 seconds.

Every call carries a secret, and every deployment gets it as the HOSTEDGE_CRON_SECRET environment variable, so your endpoint can refuse anyone else:

export default {
  async fetch(request, env) {
    const url = new URL(request.url)
    if (url.pathname === '/api/cron/digest') {
      if (request.headers.get('authorization') !== `Bearer ${env.HOSTEDGE_CRON_SECRET}`)
        return new Response('Unauthorized', { status: 401 })
      await sendDigest(env)
      return new Response('ok')
    }
    return env.ASSETS.fetch(request)
  },
}

The secret is created with your first cron job; redeploy once so your code sees it. Roll secret creates a new one (redeploy again afterwards). The request also has X-HostEdge-Cron: <job name> and a HostEdge-Cron user agent.

Retries#

Under If a run fails, choose up to three retries. A failed scheduled run is tried again 1, 5 and 15 minutes later, as long as that is before the next scheduled run; the request body says "trigger": "retry". A slot counts as failed only when its last retry fails too. Runs you start with Run now are not retried.

History and alerts#

Click a job to see its last 50 runs: when, how long, the status code and the start of the response. Run now calls it immediately, which is the quickest way to test.

After three failures in a row, members with the Developer role and up get a notification (and an email, unless they turned it off in Account › Notifications). The alert fires once until the job succeeds again.

Limits#

PlanJobs per projectShortest interval
Free21 hour
Starter105 minutes
Pro501 minute
Agency1001 minute

View this page as MarkdownAll docs as one file