Orchestrate complex async processes with finite state machines, parallel execution, and built-in scheduling.
Cano is still far from a 1.0 release. The API is subject to changes and may include breaking changes.
Overview
Cano is a high-performance orchestration engine designed for building resilient, self-healing systems in Rust. Unlike simple task queues, Cano uses Finite State Machines (FSM) to define strict, type-safe transitions between processing steps.
It excels at managing complex lifecycles where state transitions matter:
- Data Pipelines: ETL jobs with parallel processing (Split/Join) and aggregation.
- AI Agents: Multi-step inference chains with shared context and memory.
- Background Systems: Scheduled maintenance, periodic reporting, and distributed cron jobs.
The engine is built on three core concepts: Tasks for logic, Workflows for state transitions, and Schedulers for timing.
Features
- Type-Safe State Machines: Enum-driven transitions with compile-time guarantees.
- Multiple Processing Models:
Taskfor general-purpose work, plusRouterTask,PollTask,BatchTask, andSteppedTaskfor specialized shapes — mixed freely in one workflow. - Parallel Execution (Split/Join): Run tasks concurrently and join results with strategies like
All,Any,Quorum, orPartialResults. - Robust Retry Logic: Configurable strategies including exponential backoff with jitter and per-attempt timeouts.
- Circuit Breaker: Shared
CircuitBreakershort-circuits calls to failing dependencies before the retry loop, with configurable failure threshold, cool-down, and half-open probing. - Built-in Scheduling: Cron-based, interval, and manual triggers for background jobs.
- Crash Recovery: Pluggable
CheckpointStorerecords every FSM state entry;Workflow::resume_fromrehydrates a crashed run and continues. Ships with an embedded, ACIDRedbCheckpointStorebehind therecoveryfeature. - Sagas / Compensation: Pair a forward step with a
compensateaction viaCompensatableTask+register_with_compensation; if a later step fails, the engine rolls back the work already done in reverse order (and replays the rollback across a crash when checkpointing is on). - Observability: Optional
tracing(spans + events, plusTracingObserver) andmetrics(aMetricsObserverplus low-cardinality counters / histograms / gauges via themetricsfacade) features for deep insight into workflow, task, retry, split/join, circuit-breaker, scheduler, processing-loop, recovery and saga internals; plus synchronousWorkflowObserverhooks for lifecycle/failure events andResource::health()probes (Resources::check_all_health). - Performance-Focused: Minimizes heap allocations by leveraging stack-based objects wherever possible, giving you control over where allocations occur.
Everything above is opt-in and zero-cost when unused. For how the resilient, self-healing tagline maps to concrete primitives — retries, timeouts, circuit breakers, bulkheads, panic safety, checkpoint+resume, sagas, observers, health probes — see the Resilience, Recovery and Saga guides.
Simple Example: Parallel Processing
Here is a real-world example showing how to split execution into parallel tasks and join them back together.
graph TD
Start([Start]) --> Split{Split}
Split -->|Source 1| T1[FetchSourceTask 1]
Split -->|Source 2| T2[FetchSourceTask 2]
Split -->|Source 3| T3[FetchSourceTask 3]
T1 --> Join{Join All}
T2 --> Join
T3 --> Join
Join --> Complete([Complete])
use *;
use Duration;
// A task that simulates fetching data from a source.
async
Crash Recovery & Resume
Attach a CheckpointStore and the workflow records one CheckpointRow per state entered — before that state's task runs. After a crash, resume_from(workflow_id) reloads the run and re-enters the FSM at the last checkpointed state. The resumed state's task re-runs, so tasks at and after the resume point must be idempotent.
use *;
use RedbCheckpointStore; // behind the `recovery` feature
use Arc;
#
# ; ;
#
#
# async
The CheckpointStore trait is backend-agnostic (no feature flag) — implement it over Postgres, an HTTP service, anything; RedbCheckpointStore is just the batteries-included default. cargo run --example workflow_recovery --features recovery walks through a full crash-and-resume cycle. See the Recovery guide.
Sagas / Compensation
For steps that mutate external systems, write a #[saga::task(state = …)] — like a plain #[task], but its run returns the next state and an Output, and it has a compensate that undoes the step given that Output — and register it with register_with_compensation. The engine keeps a per-run compensation stack; if a later state fails, it drains the stack in reverse and runs each compensate. A clean rollback returns the original error (and clears the checkpoint log if one is attached); a failed compensate produces CanoError::CompensationFailed with the original error plus every compensation error.
use *;
use ;
#
;
With a checkpoint store attached, outputs are persisted and resume_from rehydrates the stack — so a failure after a crash still rolls back work done before it. Compensation is for single-task states only. cargo run --example saga_payment walks through a reserve-charge-ship rollback. See the Saga guide.
Documentation
For complete documentation, examples, and guides, please visit our website:
👉 https://nassor.github.io/cano/
You can also find:
- API Documentation on docs.rs
- Examples Directory in the repository
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
AI Disclosure
The primary developer of this repository uses AI coding assistants while working on Cano. At the time of writing, the assistants in regular use are:
- Claude Code (Anthropic API), and
- Qwen and DeepSeek models running locally.
All AI-assisted output is reviewed, edited, tested, and submitted by a human developer who is fully responsible for the resulting code. AI tools are treated as accelerators, not authors. See AI_USAGE_POLICY.md for the full policy that contributors are expected to follow when using AI assistants on this project.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.