Cano: Simple & Fast Async Workflows in Rust ๐
Async workflow engine with built-in scheduling, retry logic, and state machine semantics.
Cano is a lightweight, async workflow engine for Rust that turns complex processing into simple, composable workflows.
The engine is built on three core concepts: Nodes to encapsulate your business logic, Workflows to manage state transitions, and Schedulers to run your workflows on a schedule. This library-driven approach allows you to define complex processes with ease.
The Node API is inspired by the PocketFlow project, but has been re-imagined for Rust's async ecosystem with a strong focus on simplicity and performance.
โก Quick Start
Add Cano to your Cargo.toml
:
[]
= "0.1"
= "0.1"
= { = "1.0", = ["full"] }
The Simplest Example
use *;
// Define your workflow states
;
async
That's it! You just ran your first Cano workflow.
๐ฏ Why Choose Cano?
- ๐๏ธ Simple API: A single
Node
trait handles everything - no complex type hierarchies - ๐ Simple Configuration: Fluent builder pattern makes setup intuitive
- ๐ Smart Retries: Multiple retry strategies (none, fixed, exponential backoff) with jitter support
- ๐พ Shared Store: Thread-safe key-value store for data passing between nodes
- ๐ Scheduler Scheduling: Built-in scheduler for running flows on intervals, cron schedules, or manual triggers
- ๐ Complex Workflows: Chain nodes together into sophisticated state machine pipelines
- โก Type Safety: Enum-driven state transitions with compile-time safety
- ๐ High Performance: Minimal overhead with direct execution for maximum throughput
๐ How It Works
Cano is built around three simple concepts:
1. Nodes - Your Processing Units
A Node
trait is where your logic lives. Configure it once, and Cano handles the execution:
// Custom node with specific logic
;
Built-in Retry Logic
Every node includes configurable retry logic with multiple strategies:
No Retries - Fail fast for critical operations:
Fixed Retries - Consistent delays between attempts:
Exponential Backoff - Smart retry with increasing delays:
Custom Exponential Backoff - Full control over retry behavior:
Why Use Different Retry Modes?
- None: Database transactions, critical validations where failure should be immediate
- Fixed: Network calls, file operations where consistent timing is preferred
- Exponential: API calls, external services where you want to back off gracefully
- Custom Exponential: High-load scenarios where you need precise control over timing and jitter
2. Store - Share Data Between Nodes
Use the built-in store to pass data around your workflow:
let store = new;
// Store some data
store.put?;
store.put?;
// Retrieve it later
let user_id: = store.get;
let name: = store.get;
3. Workflows - Chain Nodes Together
Build complex workflows with state machine semantics:
let mut workflow = new;
workflow.register_node
.register_node
.register_node
.add_exit_states;
let result = workflow.orchestrate.await?;
Complex Workflows
Build sophisticated state machine pipelines with conditional branching, error handling, and retry logic:
graph TD
A[Start] --> B[LoadData]
B --> C{Validate}
C -->|Valid| D[Process]
C -->|Invalid| E[Sanitize]
C -->|Critical Error| F[Error]
E --> D
D --> G{QualityCheck}
G -->|High Quality| H[Enrich]
G -->|Low Quality| I[BasicProcess]
G -->|Failed & Retries Left| J[Retry]
G -->|Failed & No Retries| K[Failed]
H --> L[Complete]
I --> L
J --> D
F --> M[Cleanup]
M --> K
// Validation node with multiple possible outcomes
;
// Quality check node with conditional processing paths
;
// # ALL OTHER NODES...
// Build the complex workflow
let mut workflow = new;
workflow
.register_node
.register_node
.register_node
.register_node
.register_node
.register_node
.register_node // -> Complete
.register_node // -> Complete
.register_node // -> Process
.register_node // -> Failed
.add_exit_states;
let result = workflow.orchestrate.await?;
Scheduler - Simplified Scheduling
The Scheduler module provides an easy-to-use scheduler for running workflows on various schedules. Perfect for building background job systems, periodic data processing, and automated workflows.
Quick Start with Scheduler
use *;
use Duration;
async
Scheduler Features
- ๐ Flexible Scheduling: Support for intervals, cron expressions, and manual triggers
- โฐ Convenience Methods: Easy
every_seconds()
,every_minutes()
,every_hours()
helpers - ๐ Status Monitoring: Check workflow status, run counts, and last execution times
- ๐ง Manual Control: Trigger flows manually and monitor execution
- ๐ Graceful Shutdown: Stop with timeout to wait for running flows to complete
- ๐ Concurrent Execution: Multiple flows can run simultaneously
Advanced Scheduler Usage
// Create a more complex scheduled workflow
let mut scheduler = new;
// Data processing every hour
scheduler.every_hours?;
// Health checks every 30 seconds
scheduler.every_seconds?;
// Daily reports at 9 AM using cron
scheduler.cron?;
// Manual cleanup task
scheduler.manual?;
// Start the scheduler
scheduler.start.await?;
// Monitor running flows
spawn;
// Graceful shutdown with 30 second timeout
scheduler.stop_with_timeout.await?;
๐งช Testing & Benchmarks
Verify everything works and see performance metrics:
# Run all tests
# Run performance benchmarks
# Run workflow examples
# Run scheduler scheduling examples
๐ Documentation
- API Documentation - Complete API reference
- Examples Directory - Hands-on code examples
- Benchmarks - Performance testing and optimization
๐ค Contributing
We welcome contributions! Areas where you can help:
- ๐ Documentation - Improve guides and examples
- ๐ง Features - Add new store backends or workflow capabilities
- โก Performance - Optimize hot paths and memory usage
- ๐งช Testing - Add test cases and edge case coverage
- ๐ Bug Fixes - Report and fix issues
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
Ready to build fast, reliable workflows? Start with the examples and let Cano handle the complexity while you focus on your business logic.