Job orchestration
Your cron jobs grew up. Give them a graph.
Spindle replaces scattered crontabs and one-off CI jobs with a single scheduler: jobs declare what they depend on, Spindle decides what runs when, retries what failed, and tells you before a late run becomes an incident.
- Schedules in plain cron syntax or as an interval — plus event and manual triggers.
- Dependencies between steps, so a report never reads a half-finished table.
- Retries with backoff per step, not blunt retries of the whole pipeline.
- Agents run in your own network; Spindle never needs inbound access to your boxes.
A workflow, start to finish
Three steps, one schedule. The export waits for both loaders; if either one fails, the export is not attempted and nobody gets a wrong number.
Where it runs
Control plane in Frankfurt and Amsterdam, with a cold standby in Helsinki. Data stays in the EU; agents hold your credentials and Spindle only ever sees step names, timings and exit codes.
What teams use it for
Nightly data loads
The classic case. Twelve extracts that must finish before the warehouse rebuild starts, and a rebuild that must not start twice.
Billing and invoicing runs
Jobs that cannot be retried blindly. Spindle keeps per-step idempotency keys so a retry of step four does not re-charge anyone.
Housekeeping
Backups, log rotation, certificate renewals, cache warms. Boring work that is only visible when it silently stops happening.
A workflow is a file
Workflows live in your repository next to the code they run. Spindle picks up the definition from a Git ref or from the CLI, so a change to a schedule goes through the same review as any other change.
# spindle.yaml
workflow: warehouse-nightly
schedule: "20 2 * * *" # 02:20, agent timezone
timezone: Europe/Amsterdam
late_after: 45m # alert if not finished by then
steps:
- name: load-orders
run: "./bin/extract orders"
retries: { max: 3, backoff: 30s }
- name: load-refunds
run: "./bin/extract refunds"
retries: { max: 3, backoff: 30s }
- name: build-export
needs: [load-orders, load-refunds]
run: "./bin/export --day=$SPINDLE_RUN_DATE"
timeout: 20m
Everything else — history, logs, the dependency graph, the alert when
build-export is still running at 03:05 — comes from that file without extra
configuration.
Recent runs
| Run | Duration | Result |
|---|---|---|
| #4192 | 6m 41s | passed |
| #4191 | 7m 02s | passed |
| #4190 | 31m 18s | late |
| #4189 | 6m 55s | passed |
| #4188 | 2m 09s | failed |
| #4187 | 6m 38s | passed |
load-orders retried twice and then succeeded. Spindle paged on
the late_after budget, not on a failure that never happened.Integrations
Alerts to Slack, Mattermost, PagerDuty, Opsgenie or a plain webhook. Metrics in Prometheus format from the agent, run history over the REST API.
Try it on one workflow
Install the agent, point it at a repository, move your noisiest cron job over. Trial accounts keep full history for 14 days and need no payment details.