Configuration¶
Rustvello supports four configuration sources, applied from highest to lowest priority:
Programmatic — builder method calls (always wins)
Environment variables —
RUSTVELLO__*prefixTOML config file — loaded via
.from_file("config.toml")Defaults — compile-time defaults in
AppConfig/TaskConfig
See also: Pynenc Docs
If you are configuring Rustvello as the backend for Pynenc, see the top-level Pynenc Configuration Docs.
Mode Selection¶
When rustvello is used through pynenc, the orchestrator class controls whether orchestration uses Python-coordinated calls (mixed mode) or Rust composites (native orchestrator):
Config Field |
Example Value |
Mode |
|---|---|---|
|
|
Mixed |
|
|
Native |
|
|
Native |
|
|
Native |
The *NativeOrchestrator classes enable single-call composite orchestration for
status/result/retry hot paths. See Architecture for details.
Note
Runner-loop selection is related but separate: Pynenc.is_all_rust_native
checks whether all configured backend class names start with Rust
(orchestrator_cls, state_backend_cls, broker_cls, trigger_cls,
client_data_store_cls).
Available Class Names¶
Backend |
Mixed Mode |
Native Mode |
|---|---|---|
In-memory |
|
|
SQLite |
|
|
Redis |
|
|
PostgreSQL |
|
|
MongoDB |
|
|
Set via env var:
PYNENC__ORCHESTRATOR_CLS=RustSqliteNativeOrchestrator
PYNENC__BROKER_CLS=RustSqliteBroker
PYNENC__STATE_BACKEND_CLS=RustSqliteStateBackend
PYNENC__TRIGGER_CLS=RustSqliteTrigger
PYNENC__CLIENT_DATA_STORE_CLS=RustSqliteClientDataStore
AppConfig¶
Application-level settings that apply to the entire RustvelloApp.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Unique identifier for the application |
|
|
|
Execute tasks synchronously in-process (for testing) |
|
|
|
Max seconds an invocation can stay |
|
|
|
How often a runner publishes its heartbeat |
|
|
|
Heartbeat age threshold after which a runner is considered dead |
|
|
|
How often the management loop scans for stale invocations |
|
|
CPU count |
Number of concurrent async workers per runner |
|
|
|
Milliseconds a worker sleeps when the broker queue is empty |
|
|
|
Log level for both Rust and Python runtimes ( |
|
|
|
Log output format: |
See Logging Guide for details on the unified logging format.
TaskConfig¶
Per-task settings. Apply globally via [task_defaults] or per-task via [tasks.<name>]
in a TOML file, or via env vars.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Maximum retry attempts on failure |
|
|
|
Execution-time concurrency mode |
|
|
|
Max simultaneous running instances |
|
|
|
Registration-time dedup mode |
|
|
|
Arg names used as the concurrency key for |
|
|
|
Cache and return previous result for identical args |
|
|
|
Args excluded from cache key computation |
|
|
|
Error type names that trigger a retry |
|
|
|
Raise if a duplicate is found with different non-key args |
|
|
|
Always start a new workflow scope for this task |
|
|
|
Reroute to the existing invocation when hitting concurrency limits |
|
|
|
Batch size used by |
|
|
|
Run on a blocking (OS) thread rather than Tokio |
Concurrency Control¶
ConcurrencyControlType controls how concurrent invocations are managed:
Variant |
Behaviour |
|---|---|
|
All invocations run concurrently — no restrictions |
|
At most one invocation of this task runs at a time |
|
At most one invocation per unique full argument set |
|
No concurrent invocations allowed |
Set with the macro attribute:
#[rustvello::task(concurrency = "task")]
fn exclusive_task() -> String { ... }
#[rustvello::task(concurrency = "argument")]
fn per_user_task(user_id: u64, data: String) -> String { ... }
Or in TOML:
[task_defaults]
concurrency_control = "task"
[tasks.per_user_task]
concurrency_control = "argument"
Environment Variables¶
All AppConfig fields are overridable via RUSTVELLO__ prefix + field name in
SCREAMING_SNAKE_CASE:
RUSTVELLO__APP_ID=my-app
RUSTVELLO__MAX_PENDING_SECONDS=600
RUSTVELLO__HEARTBEAT_INTERVAL_SECONDS=15
RUSTVELLO__REDIS_URL=redis://localhost:6379
RUSTVELLO__DB_PATH=./tasks.db
Per-task overrides use the pattern RUSTVELLO__TASK__<TASK_NAME>__<FIELD>:
# Override max_retries for the "send_email" task
RUSTVELLO__TASK__SEND_EMAIL__MAX_RETRIES=5
Enable env loading in the builder:
let app = Rustvello::builder()
.app_id("my-app") // programmatic — cannot be overridden by env
.from_env() // load remaining fields from RUSTVELLO__* vars
.build().await?;
TOML Config File¶
# config.toml
app_id = "my-app"
max_pending_seconds = 600
heartbeat_interval_seconds = 15
num_workers = 4
# Global task defaults
[task_defaults]
max_retries = 1
# Per-task overrides
[tasks.process_order]
max_retries = 3
concurrency_control = "arguments"
[tasks.send_welcome_email]
concurrency_control = "keys"
key_arguments = ["user_id"]
cache_results = true
Load with the builder:
let app = Rustvello::builder()
.from_file("config.toml")?
.from_env() // env vars still win over file for anything in both
.build().await?;
Backend Connection Settings¶
Backend-specific URLs and paths are set via builder methods or environment variables:
// Programmatic
Rustvello::builder().db_path("./tasks.db").build().await?;
# Environment
RUSTVELLO__DB_PATH=./tasks.db rustvello run
// Programmatic
Rustvello::builder().redis_url("redis://localhost:6379").build().await?;
# Environment
RUSTVELLO__REDIS_URL=redis://prod-redis:6379 rustvello run
CLI Config Inspection¶
View the effective configuration (merged from all sources) with:
rustvello config --config ./config.toml --app-id my-app
This prints the resolved AppConfig as TOML to stdout, showing exactly which values
came from each source.