opencloudportDocs

Scheduled runs

Run your app's code on a timetable: every day at 9:00, every 15 minutes, on weekdays. Up to 5 per app.

An app with compute can run its code on a timetable, like a nightly report, a reminder email or tidying up old rows. Each schedule calls your code's scheduled() handler, the same as a Cloudflare Worker's Cron Triggers.

  • Up to 5 schedules per app.
  • Times are UTC, and the smallest gap is a minute.
  • Each run costs what a request to your app costs.
  • A run is skipped (with the reason) while the app is paused, has no code deployed, or its compute is still being set up. Runs missed while skipped aren't made up later.
  • What a run prints, and any error it throws, shows in the app's logs.

Your code

Export a scheduled handler next to fetch. controller.cron says which schedule fired, so one handler can do different jobs:

export default {
  async fetch(request, env) {
    return new Response('Hello')
  },

  async scheduled(controller, env, ctx) {
    if (controller.cron === '0 9 * * *') {
      const { results } = await env.DB.prepare("select count(*) as n from orders where created_at >= date('now', '-1 day')").all()
      console.log(`Orders yesterday: ${results[0].n}`)
    }
  },
}

If the handler throws, the run is marked as failed and the error is in the logs.

In the dashboard

Open the app, choose its Compute, then Schedules. Pick one in plain words (every 15 minutes, every day at a time, every weekday, every Monday, the 1st of each month) or write your own cron expression. Each schedule shows when it runs next and how its last run went. Untick On to pause one without removing it.

Cron expressions

Five parts, separated by spaces: minute, hour, day of the month, month, day of the week.

ExpressionRuns
0 9 * * *Every day at 9:00 UTC
*/15 * * * *Every 15 minutes
0 8 * * 1-5Every weekday at 8:00 UTC
30 6 * * monEvery Monday at 6:30 UTC
0 0 1 * *On the 1st of every month at midnight UTC
@daily, @hourly, @weekly, @monthlyThe usual shortcuts

Each part takes *, numbers, ranges (1-5), lists (1,15) and steps (*/10). Months and days of the week also take names (jan, mon). As in cron, when both the day of the month and the day of the week are set, a day matching either one counts.

From the API

# Replace all of the app's schedules (an empty list removes them).
curl -X PUT https://opencloudport.com/api/v1/apps/$APP_ID/schedules \
  -H "Authorization: Bearer $OCP_KEY" \
  -H "content-type: application/json" \
  -d '{ "schedules": [{ "cron": "0 9 * * *" }, { "cron": "*/15 * * * *", "enabled": false }] }'

# See them, with when each runs next and how its last run went.
curl https://opencloudport.com/api/v1/apps/$APP_ID/schedules -H "Authorization: Bearer $OCP_KEY"

Each schedule comes back with description (in plain words), next_run_at, last_run_at, last_result (ok, error or skipped) and last_detail (the reason, for errors and skips). A mistake in any expression changes nothing and says which one.

With the SDK: app.schedules.list() and app.schedules.set([{ cron: '0 9 * * *' }]). Agents have list_schedules and set_schedules.

On this page