Pipelines that finish what they start
Synchronoid runs are durable. If a worker dies in the middle of a run, the run resumes from the last finished step. Every step is safe to run twice, so retries and replays never duplicate data.
A run is a promise, not a process
Most schedulers tie a run to the worker that started it. When that worker is restarted, scaled down or crashes, the run is lost and someone has to find out. In Synchronoid the state of a run lives in the platform, not in a worker.
- Each finished step is recorded before the next one starts.
- A new worker picks up an interrupted run at the last finished step.
- Deploys do not cancel running pipelines.
- Replay any past run with
syn runs replay <run-id>.
@sy.step(source=companies, retry=sy.Retry(max_attempts=5, backoff="exponential")) def fetch_page(ctx, page: int): resp = ctx.source.get("/companies", params={"page": page}) # returns a reference, not the payload return ctx.raw.put(resp.json()) @sy.pipeline def companies_sync(): refs = [fetch_page(p) for p in range(1, 40)] return company_profiles(refs)
The boring parts, handled
You write the logic that is specific to your data. Synchronoid handles what happens when things go wrong.
Replay-safe steps
Steps write with stable keys, so running a step twice produces the same result as running it once. Re-run a failed night without cleaning up first.
Smart retries
Retries use backoff, jitter and a hard limit. Rate-limit and timeout errors are treated differently from bad data, which is never retried blindly.
Auto-pause
A source that keeps failing is paused automatically and the on-call person is alerted. No more thousands of failing runs against a broken endpoint.
Run on time, or run when something happens
Use a schedule for regular work and a sensor to react to events: a new file in a bucket, a changed row count, or a webhook from a partner.
- Cron schedules with time zones and catch-up rules.
- Sensors that poll cheaply and start a run only on a real change.
- Overlap control: skip, queue or cancel when the last run is still going.
nightly = sy.Schedule(cron="0 2 * * *", target=companies_current) @sy.sensor(target=companies_current, every="5m") def new_export_file(ctx): latest = ctx.source.head("/exports/latest.csv") if latest.etag != ctx.cursor: ctx.cursor = latest.etag return sy.RunRequest(run_key=latest.etag)
Fix history without fear
Assets can be partitioned by day, month or any key. A backfill runs only the partitions you select, in parallel, within the rate limit of the source. Because steps are replay-safe, backfilling an already loaded range is harmless.
$ syn backfill companies_current --from 2026-09-01 --to 2026-09-30 Planning 30 partitions ... done Rate budget: company_registry 120 req/min (shared) Running 4 partitions in parallel 2026-09-01 succeeded 1m 52s 2026-09-02 succeeded 1m 49s 2026-09-03 running ...
Pass references, not payloads
Steps hand each other references to data that is already stored in the raw or staged layer. Run state stays small, runs start fast, and you pay for compute instead of for moving bytes around.
companies_current, run_8f3a
Ready to stop babysitting pipelines?
Synchronoid is in private beta. Tell us about your data and we will get you a workspace.