# duroxide-cdb
[](https://crates.io/crates/duroxide-cdb)
[](LICENSE)
A CosmosDB NoSQL provider for [duroxide](https://github.com/microsoft/duroxide) — a durable execution runtime for Rust.
Stores orchestration state, event history, and work queues in a single CosmosDB container using document-type discrimination and partition-per-instance layout.
## Latest Release (0.1.10)
- Bumped duroxide dependency to `0.1.29` (replay-safe fan-in combinators; `futures` crate now optional in core)
- No source code changes in this provider
- See [CHANGELOG.md](CHANGELOG.md) for full version history
## Features
- **Single-container design** — all document types coexist, partitioned by `instanceId`
- **Transactional batch** — atomic commits within a partition (up to 100 operations)
- **Transactional outbox** — reliable cross-partition delivery for sub-orchestrations
- **Optimistic concurrency** — ETag-based locking, no database-level locks
- **Dispatch slot partitioning** — 256-slot keyspace eliminates dispatcher contention
- **Session affinity** — routes work items to the same worker by session ID
- **KV store with delta tracking** — durable per-instance key-value state using `kv_store` snapshots plus `kv_delta` current-execution mutations
- **Timestamped KV snapshots** — preserves per-key update times, supports bulk reads, and keeps orchestration snapshots isolated from in-flight KV changes
- **Runtime introspection stats** — computes per-instance history, carry-forward queue, and KV usage on demand via `Client::get_orchestration_stats()`
- **Raw REST client** — direct HTTP to CosmosDB, no Azure SDK dependency
## Quick Start
### 1. Start the CosmosDB Emulator
```bash
docker run -p 8081:8081 -p 10250-10255:10250-10255 \
mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
```
### 2. Add the dependency
```toml
[dependencies]
duroxide = "0.1.27"
duroxide-cdb = "0.1.8"
```
### 3. Create a provider and run an orchestration
```rust
use duroxide::runtime::Runtime;
use duroxide::{ActivityContext, OrchestrationContext, OrchestrationRegistry};
use duroxide::runtime::registry::ActivityRegistry;
use duroxide_cdb::CosmosDBProvider;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let provider = CosmosDBProvider::new(
"http://localhost:8081",
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
"duroxide",
).await?;
let activities = ActivityRegistry::builder()
.register("Greet", |_ctx: ActivityContext, name: String| async move {
Ok(format!("Hello, {name}!"))
})
.build();
let orchestrations = OrchestrationRegistry::builder()
.register("HelloWorld", |ctx: OrchestrationContext, name: String| async move {
let greeting = ctx.schedule_activity("Greet", name).await?;
Ok(greeting)
})
.build();
let rt = Runtime::start(Arc::new(provider), orchestrations, activities, Default::default());
let client = rt.client();
let result = client.schedule_and_wait("my-instance", "HelloWorld", "Rust", 30_000).await?;
println!("Result: {result}");
rt.shutdown().await;
Ok(())
}
```
## Configuration
### Environment Variables
| `COSMOS_ENDPOINT` | CosmosDB account endpoint | `http://localhost:8081` |
| `COSMOS_KEY` | CosmosDB account key | Emulator default key |
| `COSMOS_DATABASE` | Database name | `duroxide` |
Copy `.env.example` to `.env` for local development.
### Programmatic Configuration
```rust
use duroxide_cdb::{CosmosDBProvider, CosmosDBProviderConfig};
use std::time::Duration;
let config = CosmosDBProviderConfig {
endpoint: "https://myaccount.documents.azure.com:443/".to_string(),
key: "your-key-here".to_string(),
database: "mydb".to_string(),
container: "mycontainer".to_string(),
orch_concurrency: 2, // 2 orchestration dispatchers
worker_concurrency: 4, // 4 worker dispatchers
reconciler_interval: Duration::from_secs(2),
reconciler_age_threshold: Duration::from_secs(2),
};
let provider = CosmosDBProvider::new_with_config(config).await?;
```
## Architecture
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for comprehensive design documentation covering:
- Data model (8 document types, indexing policy, composite indexes)
- Core algorithms (fetch/ack orchestration items, work items)
- Transactional outbox pattern for cross-partition writes
- Dispatch slot partitioning (256-slot keyspace)
- Cross-partition query strategy (gateway limitations and workarounds)
- Session affinity implementation
- Error handling and retry strategy
## Data Model
All documents live in a single container with `/instanceId` as the partition key:
| `instance` | Orchestration metadata, lock state, custom status |
| `history` | Append-only event log (one doc per event) |
| `orch_queue` | Messages for the orchestration dispatcher |
| `worker_queue` | Activity execution requests |
| `outbox_intent` | Pending cross-partition writes |
| `session` | Session affinity ownership tracking |
| `kv` | Materialized per-instance key-value state from completed executions |
| `kv_delta` | Current-execution KV mutations and tombstones prior to terminal merge |
## Testing
### Prerequisites
- CosmosDB Emulator (Docker) or an Azure CosmosDB account
- [cargo-nextest](https://nexte.st/) for running tests
### Run provider validation tests
```bash
cargo nextest run --features provider-test
```
### Run e2e sample tests
```bash
cargo nextest run --test e2e_samples
```
### Run against Azure CosmosDB
Set environment variables in `.env`:
```bash
COSMOS_ENDPOINT=https://your-account.documents.azure.com:443/
COSMOS_KEY=your-primary-key
COSMOS_DATABASE=duroxide
```
## Module Structure
```
src/
├── lib.rs Re-exports CosmosDBProvider, CosmosDBProviderConfig
├── provider.rs Provider + ProviderAdmin trait implementations
├── client.rs Raw REST client (HMAC-SHA256 auth, CRUD, query, batch)
├── models.rs Serde structs for all document types
├── query.rs Cross-partition and single-partition query builders
├── batch.rs Transactional batch operations
├── containers.rs Database/container bootstrapping with retry
├── outbox.rs Outbox intent delivery + background reconciler
├── leases.rs Dispatch slot assignment (LeaseProvider trait)
└── errors.rs CosmosDB HTTP status → ProviderError mapping
```
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
## License
This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
Copyright (c) Microsoft Corporation. All Rights Reserved.