Scheduled jobs
A scheduled job makes one HTTP call to one of your organization's apps on a clock, like Google Cloud Scheduler.
What a job is made of#
The call reaches whichever version is live at that moment.
| Field | Description |
|---|---|
| App | The container app to call. |
| Path | Appended to the app's address. Starts with /; a query string is allowed. For example /tasks/daily. |
| Method | GET, POST, PUT, PATCH or DELETE; POST by default. A body is sent only with POST, PUT and PATCH. |
| Schedule | A five-field cron expression: minute, hour, day of month, month, day of week. At most once a minute. |
| Time zone | Asia/Taipei by default. |
Some cron expressions:
| Expression | Runs |
|---|---|
0 9 * * * | Every day at 09:00 |
*/15 * * * * | Every 15 minutes |
0 8 * * 1 | Every Monday at 08:00 |
0 0 1 * * | At 00:00 on the 1st of every month |
Create a job#
- Add an endpoint to your app For example
POST /tasks/daily, with the recurring work in it. Deploy it and go live. - Create the job Open Deploy › Scheduled jobs, choose the app, and enter the path and schedule.
- Run it once by hand Use Run now, then check the response code and log in the run history.
Check that a call came from the schedule#
By default a call carries no proof of where it came from. Choose one of these:
- Set your own header on the job, such as
X-Cron-Secret, store the value as a secret of the app, and compare the two in your code. - Turn on the signed token. The call then carries
Authorization: Bearer <JWT>; verify it againsthttps://api.agentlab.cresclab.com/.well-known/jwks.jsonwithaud=franky:app:<app ID>.
How runs behave#
| Item | Behavior |
|---|---|
| Overlap | Runs never overlap. A run that comes due while the previous one is still going is skipped. |
| Delivery | At least once, so a run can arrive twice. De-duplicate on the X-Franky-Run-Id header. |
| Retries | 0 by default, at most 5. |
| Deadline | 15 seconds to 30 minutes; 3 minutes by default. |
const runId = req.headers["x-franky-run-id"];
if (await alreadyHandled(runId)) {
res.writeHead(200).end();
return;
}