Cron Jobs
Cron jobs are JavaScript code snippets stored in the database and executed on a schedule using standard cron expressions. They run server-side with access to all platform services.
Database Schema
daas_cron_jobs
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
name | text | Human-readable name |
description | text | Optional description |
schedule | text | 5-field cron expression |
timezone | text | IANA timezone (e.g., Asia/Singapore) |
code | text | JavaScript code to execute |
status | text | active or inactive |
timeout_ms | integer | Maximum execution time in ms |
memory_limit_mb | integer | Sandbox memory limit in MB (default 64) |
running | boolean | Lock flag — true while executing |
running_since | timestamptz | When the current run started |
last_run_at | timestamptz | Last execution time |
last_run_status | text | running, success, error, or timeout |
next_run_at | timestamptz | Calculated next run time |
daas_cron_history
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
job_id | uuid | FK → daas_cron_jobs |
job_name | text | Job name at time of run (denormalized) |
triggered_at | timestamptz | When the job was scheduled to fire |
started_at | timestamptz | When execution actually began |
finished_at | timestamptz | When execution ended |
duration_ms | integer | Total execution time |
status | text | running, success, error, or timeout |
error | text | Error message if failed |
logs | text[] | Lines captured from console.log |
triggered_by | text | schedule, manual, or extension |
Cron Expression Reference
┌───────── minute (0–59)
│ ┌─────── hour (0–23)
│ │ ┌───── day of month (1–31)
│ │ │ ┌─── month (1–12)
│ │ │ │ ┌─ day of week (0–7, 0=Sun)
│ │ │ │ │
* * * * *| Expression | Meaning |
|---|---|
* * * * * | Every minute |
0 * * * * | Every hour |
0 0 * * * | Every day at midnight |
0 9 * * 1 | Every Monday at 9:00 AM |
*/15 * * * * | Every 15 minutes |
0 0 1 * * | First day of every month |
0 6,18 * * * | 6 AM and 6 PM daily |
Code Sandbox
Each job runs in an isolated sandbox with these globals:
| Available | Not available |
|---|---|
context — job metadata | setTimeout / setInterval |
services — platform services | require / import |
console.log/warn/error/info | eval |
| Standard JS globals | File system access |
Available services
// Items CRUD
const svc = await services.items('articles');
await svc.readByQuery({ filter: { status: { _eq: 'draft' } } });
await svc.createOne({ title: 'Auto-generated' });
await svc.updateOne(id, { processed: true });
await svc.deleteOne(id);
// Schema services
await services.collections();
await services.fields();
await services.relations();
// Files and versions
await services.files();
await services.versions();
// Send email
await services.mail({ to: 'user@example.com', subject: 'Report', html: '<p>Done</p>' });
// Trigger another cron job
await services.cron.trigger('job-id-or-name');
// Whitelisted environment variables
const apiKey = services.env.MY_API_KEY;
// Safe HTTP (domain-restricted — configure EXTENSION_ALLOWED_DOMAINS)
const res = await services.fetch('https://api.example.com/data');
// Custom services
const notifier = await services.custom('slack-notify');
// Raw Supabase (bypasses RLS — use with caution)
const { data } = await services.supabase.from('table').select('*');Example: Cleanup old records
// Delete items older than 30 days
const cutoff = new Date();
cutoff.setDate(cutoff.getDate() - 30);
const svc = await services.items('daas_activity');
const old = await svc.readByQuery({
filter: { timestamp: { _lt: cutoff.toISOString() } },
fields: ['id'],
limit: 500,
});
for (const row of old) {
await svc.deleteOne(row.id);
}
console.log(`Cleaned up ${old.length} old activity records`);REST API
| Method | Path | Description |
|---|---|---|
GET | /api/cron | List cron jobs |
POST | /api/cron | Create cron job |
GET | /api/cron/:id | Get cron job |
PATCH | /api/cron/:id | Update cron job |
DELETE | /api/cron/:id | Delete cron job |
POST | /api/cron/:id/run | Trigger job manually |
POST | /api/cron/:id/clone | Clone a job (always created inactive) |
GET | /api/cron/:id/history | Get history for one job |
GET | /api/cron/history | Get all job history |
The running lock prevents concurrent executions of the same job. If a job times out without clearing the lock, use PATCH /api/cron/:id to set running: false.
Last updated on