Scheduling
Run your pipeline on cron — no daemon, no infrastructure
One command installs an OS-native scheduler. No daemon. No service to monitor.
ondatrasql schedule "*/5 * * * *"
That’s it. The pipeline now runs every 5 minutes.
Mental Model
OndatraSQL doesn’t run a scheduler process. It writes config to your OS — systemd, launchd, or Task Scheduler — and lets the OS handle execution.
You get cron without a cron daemon. You get persistence across reboots. You get logs in standard places. You get nothing to monitor.
Commands
ondatrasql schedule "*/5 * * * *" # Install + activate
ondatrasql schedule # Show status
ondatrasql schedule remove # Uninstall
Standard 5-field cron syntax: minute hour day month weekday.
Cross-Platform
OndatraSQL detects your OS and installs the right thing.
Linux — systemd user timer
~/.config/systemd/user/ondatrasql-<id>.service
~/.config/systemd/user/ondatrasql-<id>.timer
Activated with systemctl --user enable --now. Logs in journalctl --user -u ondatrasql-<id>.
macOS — launchd
~/Library/LaunchAgents/sh.ondatra.<id>.plist
Activated with launchctl load. Logs at ~/Library/LaunchAgents/sh.ondatra.<id>.log.
Windows — Task Scheduler
Created via schtasks /create /xml. Visible in Task Scheduler GUI.
Why DAG-Level, Not Per-Model
ondatrasql schedule triggers ondatrasql run — the whole pipeline, in DAG order. Per-model schedules would break dependency ordering.
This works because of Smart CDC: models that have no upstream changes skip automatically. Scheduling the whole DAG every 5 minutes is cheap when most models skip.
13:00:00 scheduler triggers
13:00:00 raw.events (CDC: 0 new rows, skip)
13:00:00 staging.orders (CDC: source unchanged, skip)
13:00:00 mart.revenue (CDC: source unchanged, skip)
13:00:01 done — 0.4s
13:05:00 scheduler triggers
13:05:00 raw.events (CDC: 247 new rows)
13:05:00 staging.orders (CDC: 12 changed)
13:05:00 mart.revenue (CDC: rebuild)
13:05:03 done — 3.1s
The DAG runs every 5 minutes but only does work when something changed.
Project Identity
Each project gets a stable identifier in .ondatra/project-id (8 hex characters, generated on first schedule install). This file should be committed to git.
The identifier is used in the scheduler unit name so:
- Two projects with the same basename don’t collide
- Renaming or moving the project doesn’t break the schedule
- Two collaborators cloning the same repo get the same identifier
If you’re on a read-only filesystem, OndatraSQL falls back to a path hash (deterministic but path-bound).
Cron Syntax
Standard 5-field syntax:
| Pattern | Description |
|---|---|
*/5 * * * * | every 5 minutes |
0 * * * * | every hour |
0 9 * * * | daily at 09:00 |
0 0 * * 0 | weekly on Sunday at midnight |
0 0 1 * * | monthly on the 1st |
0 22 * * 1-5 | weekdays at 22:00 |
Each backend supports a slightly different subset of cron syntax. OndatraSQL validates and rejects expressions the target backend cannot represent — better to fail at install than to silently install a wrong schedule.
Reading the Status
$ ondatrasql schedule
Schedule for "myproject"
Backend: systemd
Unit: ondatrasql-3f2a91b4.timer
Cron: */5 * * * * (every 5 minutes)
Status: active
Last run: Tue 2026-04-08 14:00:01 UTC
Next run: Tue 2026-04-08 14:05:00
The original cron expression is round-tripped from the unit file — what you installed is what you see.
Removing
$ ondatrasql schedule remove
Removed schedule for "myproject"
This stops the timer, disables it, and deletes the unit files. Any running pipeline finishes; no in-flight commits are interrupted.
Why This Matters
Most data tools require a separate scheduler — Airflow, Prefect, Dagster, cron containers. They each come with their own deployment, monitoring, and failure modes.
OndatraSQL doesn’t add a scheduler. It uses the one your OS already has.
| Need | Traditional stack | OndatraSQL |
|---|---|---|
| Scheduler | Airflow / Prefect / cron container | Built into the OS |
| Daemon | Always-on Python process | None |
| Monitoring | Custom dashboards | journalctl / Console.app / Event Viewer |
| Restart on reboot | systemd unit wrapping the daemon | systemd unit |
| Restart on crash | Health checks | systemd Restart= |
| Setup | Hours | One command |
The best scheduler is the one you don’t have to install.
Ondatra Labs