| layout | title | category |
|---|---|---|
default |
Development Guide |
development |
This guide covers development setup, contributing guidelines, testing procedures, and architectural considerations for Orbit-RS development.
- Rust 1.70+ - Install via rustup
- Protocol Buffers compiler (
protoc) - Required for gRPC code generation - Git - Version control system
- IDE/Editor with Rust support (VS Code, IntelliJ IDEA, or Neovim)
- CMake - Required for building RocksDB native dependencies
- Clang/LLVM - C++ compiler for native dependencies
# Clone the repository
git clone https://github.com/TuringWorks/orbit-rs.git
cd orbit-rs
# Install system dependencies (macOS)
brew install protobuf cmake llvm
# Install system dependencies (Ubuntu/Debian)
sudo apt-get update
sudo apt-get install -y protobuf-compiler cmake clang
# Install Rust toolchain components
rustup component add clippy rustfmt
# Install development tools
cargo install cargo-audit
cargo install cargo-deny
cargo install cargo-tarpaulin # For code coverage
# Build all modules (including persistence backends)
cargo build --workspace
# Run tests to verify setup
cargo test --workspace
# Verify persistence modules specifically
cargo test --lib --package orbit-serverRecommended extensions:
- rust-analyzer - Rust language server with excellent IntelliSense
- CodeLLDB - Debugger support for Rust
- crates - Cargo dependency management
- Better TOML - TOML file syntax highlighting
- GitLens - Enhanced Git capabilities
VS Code settings (.vscode/settings.json):
{
"rust-analyzer.cargo.features": "all",
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.checkOnSave.extraArgs": ["--", "-D", "warnings"],
"rust-analyzer.cargo.buildScripts.enable": true,
"files.watcherExclude": {
"**/target/**": true
}
}- Install the Rust plugin
- Configure the Rust toolchain in Settings → Languages & Frameworks → Rust
- Enable Use Clippy instead of Cargo Check
- Configure Code Style → Rust to use rustfmt
# Fast compilation check (no codegen) - includes persistence backends
cargo check --workspace
# Full compilation with all features
cargo build --workspace --all-features
# Release build with optimizations
cargo build --workspace --release
# Run all tests including persistence layer
cargo test --workspace
# Test specific modules
cargo test --lib --package orbit-server # Persistence modules
cargo test --lib --package orbit-shared # Core types
# Code formatting
cargo fmt --all
# Linting (persistence modules now pass)
cargo clippy --workspace --all-targets
# Security audit
cargo audit
# License and dependency checking
cargo deny check
# Generate documentation
cargo doc --workspace --open
# Run persistence benchmarks
cargo run --package orbit-benchmarks
# Run protocol-specific benchmarks
cargo bench --workspaceorbit-rs/
├── Cargo.toml # Workspace configuration
├── README.md # Project overview
├── LICENSE-MIT # MIT license
├── LICENSE-BSD # BSD license
│
├── orbit-util/ # Utilities and base functionality
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── config.rs # Configuration management
│ ├── logging.rs # Logging utilities
│ └── metrics.rs # Metrics utilities
│
├── orbit-shared/ # Shared data structures and types
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── actor.rs # Actor trait definitions
│ ├── error.rs # Error types
│ ├── key.rs # Actor key types
│ └── transactions/ # Transaction system
│ ├── mod.rs
│ ├── coordinator.rs
│ ├── participant.rs
│ └── saga.rs
│
├── orbit-proto/ # Protocol Buffer definitions
│ ├── Cargo.toml
│ ├── build.rs # Proto compilation
│ ├── proto/
│ │ ├── actor.proto # Actor service definitions
│ │ ├── cluster.proto # Cluster management
│ │ └── transaction.proto
│ └── src/
│ ├── lib.rs
│ └── generated/ # Generated gRPC code
│
├── orbit-client/ # Client-side actor system
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── client.rs # Main client implementation
│ ├── proxy.rs # Actor proxy generation
│ └── lease.rs # Lease management
│
├── orbit-server/ # Server-side cluster management
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── server.rs # Main server implementation
│ ├── cluster.rs # Cluster management
│ ├── load_balancer.rs
│ └── persistence/ # Multiple storage backends
│ ├── mod.rs # Persistence traits and config
│ ├── memory.rs # In-memory provider
│ ├── cow_btree.rs # COW B+Tree provider
│ ├── lsm_tree.rs # LSM-Tree provider
│ └── rocksdb.rs # RocksDB provider
│
├── orbit-protocols/ # Protocol adapters
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── redis/ # Redis RESP protocol
│ ├── postgres_wire/ # PostgreSQL wire protocol
│ └── mcp/ # Model Context Protocol
│
├── orbit-operator/ # Kubernetes operator
│ ├── Cargo.toml
│ ├── deploy/ # Kubernetes manifests
│ └── src/
│ ├── main.rs
│ ├── controller.rs
│ └── resources/
│
│ ├── hello-world/ # Basic actor example
│ ├── distributed-counter/ # Multi-actor coordination
│ └── tests/
│ ├── features/ # BDD scenarios
│ └── tests/ # Integration tests
│
├── docs/ # Documentation
│ ├── README.md # Documentation index
│ ├── OVERVIEW.md # Project overview
│ ├── QUICK_START.md # Quick start guide
│ ├── features/ # Feature documentation
│ ├── protocols/ # Protocol documentation
│ ├── deployment/ # Deployment guides
│ └── development/ # Development guides
│
└── scripts/ # Development scripts
├── prepare-secrets.sh # CI/CD secret preparation
├── build-docker.sh # Docker image building
└── run-benchmarks.sh # Benchmark execution
- Fundamental types and utilities
- Actor trait definitions
- Error handling
- Configuration management
- Logging and metrics utilities
- Protocol Buffer definitions
- gRPC service specifications
- Message serialization/deserialization
- Cross-language type definitions
- Actor proxy generation
- Remote invocation handling
- Lease management
- Connection pooling
- Cluster node management
- Actor lifecycle management
- Load balancing
- Health monitoring
- Redis RESP protocol adapter
- PostgreSQL wire protocol adapter
- SQL parser and executor
- MCP server implementation
- Kubernetes Custom Resource Definitions
- Operator controller logic
- Resource management
- Deployment automation
Orbit-RS supports multiple pluggable storage backends:
- Hash-map based storage for development and testing
- No persistence across restarts
- Fastest performance for temporary data
- Copy-on-Write B+ Tree with Write-Ahead Logging
- Optimized for read-heavy workloads
- Snapshots and versioning support
- Log-Structured Merge Tree implementation
- Optimized for write-heavy workloads
- Background compaction and bloom filters
- Production-grade key-value store
- ACID transactions and crash recovery
- High-performance with tunable parameters
use orbit_server::persistence::*;
// Configure persistence backend
let config = PersistenceConfig {
backend: BackendType::RocksDB,
rocksdb: Some(RocksDbConfig {
data_dir: "./orbit_data".to_string(),
enable_wal: true,
block_cache_size: 256 * 1024 * 1024, // 256MB
..Default::default()
}),
..Default::default()
};
let provider = DynamicPersistenceProvider::new(config).await?;-
Implement Required Traits:
impl PersistenceProvider for MyCustomProvider { async fn initialize(&self) -> OrbitResult<()> { /* ... */ } async fn shutdown(&self) -> OrbitResult<()> { /* ... */ } // ... other methods } impl AddressableDirectoryProvider for MyCustomProvider { async fn store_lease(&self, lease: &AddressableLease) -> OrbitResult<()> { /* ... */ } // ... other methods }
-
Add Configuration Support:
#[derive(Debug, Clone, Serialize, Deserialize)] pub struct MyCustomConfig { pub connection_string: String, pub pool_size: usize, }
-
Register Backend:
// In persistence/mod.rs pub enum BackendType { Memory, CowBTree, LsmTree, RocksDB, MyCustom, // Add here }
-
Write Tests:
#[tokio::test] async fn test_my_custom_provider() { let config = MyCustomConfig { /* ... */ }; let provider = MyCustomProvider::new(config)?; provider.initialize().await?; // Test CRUD operations let lease = AddressableLease { /* ... */ }; provider.store_lease(&lease).await?; let retrieved = provider.get_lease(&lease.reference).await?; assert_eq!(retrieved.unwrap(), lease); }
# Test all persistence backends
cargo test --lib --package orbit-server persistence
# Test specific backend
cargo test --lib --package orbit-server persistence::rocksdb
# Benchmark persistence performance
cargo run --package orbit-benchmarks
# Test with different configurations
ORBIT_PERSISTENCE_BACKEND=rocksdb cargo test persistence_integrationtests/
├── unit/ # Unit tests (in src/ directories)
├── integration/ # Integration tests
│ ├── actor_lifecycle.rs
│ ├── cluster_management.rs
│ └── transaction_tests.rs
├── bdd/ # Behavior-driven tests
│ ├── features/
│ │ ├── actor_lifecycle.feature
│ │ └── messaging.feature
│ └── step_definitions/
└── benchmarks/ # Performance benchmarks
├── actor_throughput.rs
└── transaction_latency.rs
# All tests
cargo test --workspace
# Unit tests only
cargo test --workspace --lib
# Integration tests
cargo test --workspace --test integration
# BDD scenarios
cargo test --workspace --test bdd
# Specific test module
cargo test --package orbit-client --test client_tests
# Tests with output
cargo test --workspace -- --nocapture
# Parallel test execution
cargo test --workspace --jobs 4Test configuration in Cargo.toml:
[dev-dependencies]
tokio-test = "0.4"
mockall = "0.11"
cucumber = "0.19"
criterion = "0.5"
[[test]]
name = "integration"
path = "tests/integration/mod.rs"
required-features = ["integration-tests"]
[[bench]]
name = "actor_throughput"
harness = false#[cfg(test)]
mod tests {
use super::*;
use tokio_test;
#[tokio::test]
async fn test_actor_invocation() {
let client = OrbitClient::builder()
.with_namespace("test")
.build()
.await
.unwrap();
let actor = client.actor_reference::<dyn TestActor>(
Key::StringKey { key: "test-actor".to_string() }
).await.unwrap();
let result = actor.test_method("input").await.unwrap();
assert_eq!(result, "expected_output");
}
}use orbit_client::OrbitClient;
use orbit_server::OrbitServer;
use std::time::Duration;
#[tokio::test]
async fn test_cluster_communication() {
// Start server
let server = OrbitServer::builder()
.with_port(8080)
.build()
.await
.unwrap();
// Start client
let client = OrbitClient::builder()
.with_endpoint("http://localhost:8080")
.build()
.await
.unwrap();
// Test communication
// ... test logic
}Feature file (tests/features/actor_lifecycle.feature):
Feature: Actor Lifecycle Management
Scenario: Actor activation and deactivation
Given a cluster with 3 nodes
When I request an actor "test-actor"
Then the actor should be activated on one node
And the actor should respond to messages
When the actor is idle for 5 minutes
Then the actor should be deactivatedStep definitions:
use cucumber::{given, when, then, World};
#[derive(Debug, Default, World)]
pub struct ActorWorld {
cluster: Option<TestCluster>,
actor: Option<ActorReference>,
}
#[given("a cluster with {int} nodes")]
async fn given_cluster(world: &mut ActorWorld, node_count: i32) {
world.cluster = Some(TestCluster::new(node_count as usize).await);
}
#[when("I request an actor {string}")]
async fn when_request_actor(world: &mut ActorWorld, actor_id: String) {
let client = world.cluster.as_ref().unwrap().client();
world.actor = Some(client.actor_reference(&actor_id).await.unwrap());
}use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId};
use tokio::runtime::Runtime;
fn actor_throughput_benchmark(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
c.bench_with_input(
BenchmarkId::new("actor_invocation", "1000_messages"),
&1000,
|b, &size| {
b.to_async(&rt).iter(|| async {
// Benchmark actor invocation throughput
for _ in 0..size {
// Invoke actor method
}
});
},
);
}
criterion_group!(benches, actor_throughput_benchmark);
criterion_main!(benches);Use rustfmt for consistent code formatting:
# Format all code
cargo fmt --all
# Check formatting without changing files
cargo fmt --all -- --checkRustfmt configuration (.rustfmt.toml):
edition = "2021"
max_width = 100
tab_spaces = 4
newline_style = "Unix"
use_small_heuristics = "Default"
reorder_imports = true
reorder_modules = true
remove_nested_parens = trueUse Clippy for comprehensive linting:
# Run all lints
cargo clippy --workspace --all-targets -- -D warnings
# Fix automatically fixable lints
cargo clippy --workspace --all-targets --fixClippy configuration in Cargo.toml:
[workspace.lints.clippy]
pedantic = "warn"
nursery = "warn"
cargo = "warn"
missing_docs_in_private_items = "allow"
module_name_repetitions = "allow"- Public APIs: All public functions, structs, enums, and modules must have documentation
- Examples: Include usage examples in documentation
- Error Handling: Document error conditions and return types
- Safety: Document unsafe code with safety requirements
Documentation example:
/// Manages the lifecycle of actors in the Orbit cluster.
///
/// The `ActorManager` coordinates actor activation, deactivation, and
/// message routing across cluster nodes. It implements load balancing
/// and health monitoring for optimal performance.
///
/// # Examples
///
/// ```
/// use orbit_server::ActorManager;
///
/// let manager = ActorManager::new(config).await?;
/// let actor = manager.get_or_create_actor("my-actor").await?;
/// ```
///
/// # Errors
///
/// Returns [`ActorError::CreationFailed`] if actor creation fails due to
/// resource constraints or configuration issues.
pub struct ActorManager {
// Implementation details
}- Use
Result<T, E>for fallible operations - Create specific error types for different failure modes
- Provide context in error messages
- Use
anyhowfor application errors, custom error types for library APIs
Error type example:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ActorError {
#[error("Actor not found: {actor_id}")]
NotFound { actor_id: String },
#[error("Actor creation failed: {reason}")]
CreationFailed { reason: String },
#[error("Network error: {0}")]
NetworkError(#[from] std::io::Error),
#[error("Serialization error: {0}")]
SerializationError(#[from] serde_json::Error),
}-
Fork and Clone
git clone https://github.com/your-username/orbit-rs.git cd orbit-rs git remote add upstream https://github.com/TuringWorks/orbit-rs.git -
Create Feature Branch
git checkout -b feature/amazing-new-feature
-
Make Changes
- Write code following the style guide
- Add tests for new functionality
- Update documentation
- Run tests and ensure they pass
-
Commit Changes
git add . git commit -m "feat: add amazing new feature"
-
Push and Create PR
git push origin feature/amazing-new-feature # Create pull request through GitHub UI
Follow conventional commit format:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Formatting changesrefactor: Code refactoringtest: Adding testschore: Maintenance tasks
Examples:
feat(client): add connection pooling support
fix(server): resolve actor lifecycle race condition
docs(readme): update installation instructions
-
Pre-submission Checklist
- Tests pass locally
- Code is formatted (
cargo fmt) - No linting errors (
cargo clippy) - Documentation updated
- CHANGELOG.md updated (for significant changes)
-
PR Description
- Clear description of changes
- Link to related issues
- Screenshots/examples if applicable
- Breaking changes noted
-
Review Process
- Automated CI checks must pass
- At least one maintainer approval required
- Address review feedback
- Squash commits before merge (if requested)
- Keep PRs focused and reasonably sized
- Provide clear description and context
- Respond to feedback promptly
- Test edge cases and error conditions
- Check for correctness and clarity
- Verify test coverage
- Consider performance implications
- Review documentation updates
- Be constructive in feedback
- Separation of Concerns: Each module has a clear, well-defined responsibility
- Modularity: Components can be developed and tested independently
- Extensibility: Easy to add new features without breaking existing functionality
- Performance: Optimize for common use cases while maintaining flexibility
- Safety: Leverage Rust's type system for memory safety and thread safety
- Use
tokiofor async runtime - Prefer
async/awaitover manualFutureimplementations - Use structured concurrency patterns
- Handle cancellation gracefully
Example:
use tokio::time::{timeout, Duration};
pub async fn process_with_timeout<T>(
future: impl Future<Output = T>,
timeout_duration: Duration,
) -> Result<T, TimeoutError> {
timeout(timeout_duration, future)
.await
.map_err(|_| TimeoutError::Elapsed)
}- Use specific error types for different modules
- Implement
Fromtraits for error conversion - Provide helpful error messages with context
- Log errors at appropriate levels
- Minimize allocations in hot paths
- Use zero-copy techniques where possible
- Profile performance-critical code
- Document performance characteristics
use tracing::{info, warn, error, debug, trace};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
fn init_logging() {
tracing_subscriber::registry()
.with(fmt::layer())
.with(EnvFilter::from_default_env())
.init();
}
// Usage
info!("Actor {} activated", actor_id);
warn!("High memory usage detected: {}MB", memory_usage);
error!("Failed to connect to database: {}", error);# CPU profiling with perf
cargo build --release
perf record --call-graph=dwarf ./target/release/orbit-server
perf report
# Memory profiling with valgrind
cargo build
valgrind --tool=memcheck --leak-check=full ./target/debug/orbit-server
# Benchmarking
cargo bench- gdb/lldb: Traditional debuggers
- rust-analyzer: IDE integration for debugging
- tokio-console: Async runtime debugging
- tracing: Structured logging and instrumentation
- Quick Start Guide - Getting started with Orbit-RS
- Overview - Architecture and features overview
- Transaction Features - Advanced transaction development
- Protocol Adapters - Protocol development
- Deployment Guide - Production deployment