Cruster
A Rust framework for building distributed, stateful entity systems with durable workflows.
Status: Under active development. API may change. Feedback welcome.
Features
- Distributed Entities - Stateful actors with automatic sharding, persistence, and lifecycle management
- Durable Workflows - Long-running operations that survive crashes with automatic replay
- Activity Journaling - State mutations with transactional guarantees and idempotency
- Entity Traits - Composable behaviors across multiple entity types
- Singletons - Cluster-wide unique instances with automatic failover
- Timers & Scheduling - Durable sleep and cron-based scheduling
- gRPC Transport - Inter-node communication with streaming support
Installation
Prerequisites
Protocol Buffers compiler is required:
# Debian/Ubuntu
# macOS
Cargo
[]
= "0.0.2"
Quick Start
Defining an Entity
use *;
use ;
// 1. Define persistent state
// 2. Define the entity
;
// 3. Implement handlers
Using the Entity
use TestCluster;
use EntityId;
async
Core Concepts
Method Types
| Attribute | Purpose | Self | Journaled | Default Visibility |
|---|---|---|---|---|
#[rpc] |
Read-only queries | &self |
No | #[public] |
#[workflow] |
Durable operations | &self |
Yes | #[public] |
#[activity] |
State mutations | &mut self |
Yes | #[private] |
The Workflow + Activity Pattern
Best Practice: Separate concerns between workflows (orchestration) and activities (mutation).
Visibility Modifiers
Durable Workflows
Workflows survive crashes. On restart, the journal replays and completed activities return cached results:
pub async
Durable Timers
use Duration;
pub async
Entity Traits (Composition)
Share behavior across entity types:
// Define a trait
;
// Use trait in entity
Entity Configuration
;
Self-Scheduling
Entities can schedule messages to themselves:
pub async
pub async
Singletons
Cluster-wide unique instances:
use register_singleton;
register_singleton.await?;
Testing
TestCluster
use TestCluster;
use EntityId;
async
Client Methods
// Request-response
let result: Response = client.send.await?;
// Fire-and-forget
client.notify.await?;
// Persisted (at-least-once delivery)
let result: Response = client.send_persisted.await?;
// Scheduled delivery
client.notify_at.await?;
Production Deployment
Multi-Node Cluster
use ShardingConfig;
use ShardingImpl;
let config = ShardingConfig ;
let sharding = new.await?;
sharding.register_entity.await?;
sharding.start.await?;
Storage Requirements
PostgreSQL - State persistence, message storage, workflow journals
etcd - Runner discovery, shard locks, health monitoring
Configuration Reference
| Option | Default | Description |
|---|---|---|
shards_per_group |
2048 | Shards per shard group |
entity_max_idle_time |
60s | Idle timeout before eviction |
entity_mailbox_capacity |
100 | Per-entity message queue size |
storage_poll_interval |
500ms | Message storage polling frequency |
storage_message_max_retries |
10 | Max delivery attempts |
Architecture
┌─────────────────────────────────────────────────────────┐
│ Clients │
└─────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Sharding Layer │
│ Consistent hashing + request routing │
└─────────────────────────┬───────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Runner 1 │ │ Runner 2 │ │ Runner 3 │
│ Shards │ │ Shards │ │ Shards │
│ 0-682 │ │ 683-1365 │ │1366-2047 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└───────────────┴───────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ PostgreSQL│ │ etcd │
│ - State │ │ - Runners │
│ - Journals│ │ - Locks │
│ - Messages│ │ - Health │
└───────────┘ └───────────┘
Examples
See examples/ for complete examples:
- cluster-tests - E2E test suite covering all features
- chess-cluster - Distributed chess server with matchmaking
License
MIT