Skip to main content
Cloacina Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Configuration Reference

Configuration Reference

This page documents all configuration options for the Cloacina runtime. Configuration is specified programmatically via DefaultRunnerConfig (Rust API), through ~/.cloacina/config.toml (daemon/server), or via environment variables.

Server flags (cloacina-server)

When you run Cloacina as a service, the cloacina-server binary takes these command-line flags (most also accept an environment variable). The cloacinactl server start wrapper forwards the same settings.

Flag Env var Default Purpose
--bind 127.0.0.1:8080 HTTP listen address. Set 0.0.0.0:8080 to accept remote connections (containers, behind a proxy). The server exposes a single HTTP port.
--database-url DATABASE_URL (required) Postgres or SQLite connection URL.
--bootstrap-key CLOACINA_BOOTSTRAP_KEY auto-generated First-run admin key; if unset, one is generated and written once to ~/.cloacina/bootstrap-key.
--require-signatures CLOACINA_REQUIRE_SIGNATURES off Reject unsigned package uploads. Requires --verification-org-id.
--verification-org-id CLOACINA_VERIFICATION_ORG_ID Trusted org UUID for signature verification (mandatory when signatures are required).
--tenant-runner-cache-size CLOACINA_TENANT_RUNNER_CACHE_SIZE 256 LRU cap on cached per-tenant runners.
--default-executor CLOACINA_DEFAULT_EXECUTOR default Executor every task is dispatched to; set fleet to route to the execution-agent fleet.
--reconcile-interval-s runtime default Seconds between reconciler passes.
--log-retention-days 14 Daily-rotated log files to keep (0 = unbounded).
--home ~/.cloacina Home directory for keys, logs, config.
-v, --verbose off Debug logging (overrides RUST_LOG).

For the full deployment walkthrough see Deploying the API Server and Running the server image.

DefaultRunnerConfig

The DefaultRunnerConfig struct controls all runtime behavior of the DefaultRunner. Create one with the builder pattern:

use cloacina::runner::DefaultRunnerConfig;
use std::time::Duration;

let config = DefaultRunnerConfig::builder()
    .max_concurrent_tasks(8)
    .task_timeout(Duration::from_secs(600))
    .enable_cron_scheduling(false)
    .build();

Concurrency

Field Type Default Description
max_concurrent_tasks usize 4 Maximum number of task executions running simultaneously. Controls the semaphore size for the task executor.
scheduler_poll_interval Duration 100ms How often the task scheduler checks for tasks whose dependencies are satisfied and are ready to execute.
task_timeout Duration 300s (5 min) Maximum time allowed for a single task to execute before it is considered timed out.
pipeline_timeout Option<Duration> Some(3600s) (1 hr) Maximum time for an entire pipeline execution. None disables the pipeline-level timeout.
db_pool_size u32 10 Number of database connections in the connection pool.
enable_recovery bool true Whether the stale-claim sweeper runs to reclaim task executions whose runner heartbeats expired. The sweeper is the sole task-recovery path — recovery is heartbeat-driven only. Disable only if you’re running outside the standard runner loop.

Cron Scheduling

Field Type Default Description
enable_cron_scheduling bool true Master switch for cron scheduling. When disabled, no cron schedules are evaluated.
cron_poll_interval Duration 30s How often the cron scheduler checks for schedules that are due.
cron_max_catchup_executions usize usize::MAX Maximum number of missed cron executions to catch up on after downtime. Set to a finite value to cap catchup behavior.
cron_enable_recovery bool true Whether recovery of lost/failed cron executions is enabled.
cron_recovery_interval Duration 300s (5 min) How often the recovery system scans for lost cron executions.
cron_lost_threshold_minutes i32 10 Minutes after which a started-but-not-completed cron execution is considered lost.
cron_max_recovery_age Duration 86400s (24 hr) Executions older than this are not recovered. Prevents unbounded catchup on long outages.
cron_max_recovery_attempts usize 3 Maximum number of recovery attempts per cron execution before it is abandoned.

Trigger Scheduling

Field Type Default Description
enable_trigger_scheduling bool true Master switch for trigger-based scheduling.
trigger_base_poll_interval Duration 1s Base interval for checking trigger readiness. Individual triggers can define their own interval.
trigger_poll_timeout Duration 30s Timeout for a single trigger poll operation.

Registry

Field Type Default Description
enable_registry_reconciler bool true Whether the background registry reconciler runs to detect new/removed workflow packages.
registry_reconcile_interval Duration 60s How often the reconciler scans for changes.
registry_enable_startup_reconciliation bool true Whether to run a full reconciliation pass on startup.
registry_storage_path Option<PathBuf> None Custom path for filesystem-based registry storage. None uses the default location.
registry_storage_backend String "filesystem" Storage backend type. Options: "filesystem", "database". The server start command uses "database".

Task Claiming

Task claiming enables horizontal scaling by allowing multiple runner instances to coordinate work.

Field Type Default Description
enable_claiming bool true Whether task claiming is enabled. When enabled, tasks are claimed via the database before execution.
heartbeat_interval Duration 10s How often a runner sends heartbeats for its claimed tasks.
stale_claim_sweep_interval Duration 30s How often to scan for claims whose heartbeats have expired.
stale_claim_threshold Duration 60s How old a heartbeat must be before the claim is considered stale and can be reclaimed.

Runner Identity

Field Type Default Description
runner_id Option<String> None Optional unique identifier for this runner instance. Used in logs and claim ownership.
runner_name Option<String> None Optional human-readable name for this runner instance.

Tuning the cron knobs

The defaults work for most deployments. The cases where you should deviate:

  • cron_max_catchup_executions (default usize::MAX — unbounded) caps how many missed cron firings are caught up after downtime. The default replays every missed firing; a daemon offline for an hour with a per-minute cron schedule will replay 60 executions on startup. Set this to a small finite value (e.g. 10) for workflows where missed firings are stale and should be skipped, not recovered. Examples: dashboards, hourly aggregations whose inputs have already advanced.
  • cron_recovery_interval (default 300s) is how often the recovery scanner looks for lost cron executions. Lower it (e.g. 60s) for high-frequency cron schedules where a 5-minute detection delay is too long. Raise it if recovery scans contend with primary workload.
  • cron_lost_threshold_minutes (default 10) is the heartbeat- miss window before a started-but-not-completed cron execution is reclaimed. Increase it if your cron tasks legitimately take longer than 10 minutes; otherwise the recovery system will reclaim a still- running execution and start a duplicate. Decrease it for fast cron workloads where 10 minutes is too long to tolerate a stuck task.
  • cron_max_recovery_age (default 86400s — 24h) caps how old an execution can be before recovery gives up. Raise it if you expect long outages from which you genuinely want full recovery. Lower it on systems where stale executions are noise rather than signal.
  • cron_max_recovery_attempts (default 3) limits how many times recovery will retry a failing reclaim before abandoning it. Raise for transient-error tolerance; lower for fast failure isolation.

Example: a daemon scheduling hourly summary jobs that should never duplicate or backfill more than the last hour:

DefaultRunnerConfig::builder()
    .cron_max_catchup_executions(1)
    .cron_recovery_interval(Duration::from_secs(60))
    .cron_lost_threshold_minutes(15)  // Allow up to 15 min for the job
    .cron_max_recovery_age(Duration::from_secs(3600))
    .build()

DefaultRunnerConfigBuilder

All builder methods consume and return self for chaining. Each method corresponds directly to a config field:

DefaultRunnerConfig::builder()
    // Concurrency
    .max_concurrent_tasks(8)
    .scheduler_poll_interval(Duration::from_millis(200))
    .task_timeout(Duration::from_secs(600))
    .pipeline_timeout(Some(Duration::from_secs(7200)))
    .db_pool_size(20)
    .enable_recovery(true)

    // Cron
    .enable_cron_scheduling(true)
    .cron_poll_interval(Duration::from_secs(60))
    .cron_max_catchup_executions(100)
    .cron_enable_recovery(true)
    .cron_recovery_interval(Duration::from_secs(300))
    .cron_lost_threshold_minutes(15)
    .cron_max_recovery_age(Duration::from_secs(86400))
    .cron_max_recovery_attempts(5)

    // Triggers
    .enable_trigger_scheduling(true)
    .trigger_base_poll_interval(Duration::from_secs(5))
    .trigger_poll_timeout(Duration::from_secs(60))

    // Registry
    .enable_registry_reconciler(true)
    .registry_reconcile_interval(Duration::from_secs(30))
    .registry_enable_startup_reconciliation(true)
    .registry_storage_path(Some(PathBuf::from("/custom/path")))
    .registry_storage_backend("database")

    // Claiming
    .enable_claiming(true)
    .heartbeat_interval(Duration::from_secs(10))
    // Note: stale_claim_sweep_interval and stale_claim_threshold are struct
    // fields on DefaultRunnerConfig but are NOT available as builder methods.
    // They use their default values (30s and 60s respectively) when using
    // the builder. To customize them, modify the struct fields directly
    // after calling .build().

    // Identity
    .runner_id(Some("runner-01".to_string()))
    .runner_name(Some("Primary Runner".to_string()))

    .build();

DefaultRunnerBuilder

For constructing a DefaultRunner instance with database and schema configuration:

use cloacina::runner::DefaultRunnerBuilder;

// Single-tenant PostgreSQL
let runner = DefaultRunnerBuilder::new()
    .database_url("postgresql://user:pass@localhost/cloacina")
    .build()
    .await?;

// Multi-tenant with schema isolation
let tenant_runner = DefaultRunnerBuilder::new()
    .database_url("postgresql://user:pass@localhost/cloacina")
    .schema("tenant_acme")
    .with_config(config)
    .build()
    .await?;
Method Description
database_url(&str) Sets the database connection URL (required)
schema(&str) Sets the PostgreSQL schema for multi-tenant isolation. Must be alphanumeric + underscores. PostgreSQL only.
with_config(DefaultRunnerConfig) Sets the full runner configuration
runtime(Runtime) Sets a scoped Runtime for this runner. When set, the runner and all its components use this runtime’s registries instead of the process-global registries. If not set, Runtime::from_global() is used.
build() Builds and starts the runner (creates DB, runs migrations, starts background services)

config.toml

The daemon and server read ~/.cloacina/config.toml. See the CLI Reference for the full schema and key paths.

Mapping to DefaultRunnerConfig

The daemon maps config.toml values to DefaultRunnerConfig fields:

config.toml Key DefaultRunnerConfig Field
daemon.poll_interval_ms cron_poll_interval (via CLI --poll-interval)
daemon.trigger_poll_interval_ms trigger_base_poll_interval
daemon.cron_max_catchup cron_max_catchup_executions
daemon.cron_recovery_interval_s cron_recovery_interval

Note: daemon.cron_lost_threshold_min exists in config.toml but is not currently wired to DefaultRunnerConfig in the daemon command. The cron_lost_threshold_minutes field uses its default value (10 minutes).

The server uses DefaultRunnerConfig::builder().registry_storage_backend("database").build().

[server] section

The [server] section configures server-level deployment knobs read by cloacinactl server start (which forwards them to the cloacina-server binary):

config.toml Key Default Description
server.default_executor "default" Executor key every task is dispatched to. There is no per-task routing — all work goes to this one executor. "default" is the in-process thread executor; set "fleet" to offload all work to the execution-agent fleet. The key is hard-matched against registered executors at server startup; an unknown key fails fast (no silent fallback).
[server]
default_executor = "fleet"

Overrides for ad-hoc/direct runs use cloacina-server --default-executor <key>, cloacinactl server start --default-executor <key>, or CLOACINA_DEFAULT_EXECUTOR=<key>. Precedence: explicit CLI/env > config.toml [server].default_executor > built-in default.

Environment Variables

Variable Description
DATABASE_URL Database connection URL for server start and admin commands
CLOACINA_BOOTSTRAP_KEY Bootstrap API key for server start first startup
CLOACINA_DEFAULT_EXECUTOR Executor key every task is dispatched to (overrides [server].default_executor; default default, set fleet for the agent fleet)
RUST_LOG Log filter directive (e.g., info, debug, cloacina=trace)

Schema naming rules

PostgreSQL schema names used for multi-tenant isolation (DefaultRunner::with_schema, DatabaseAdmin tenant provisioning) are validated before use in SQL to prevent injection. A schema name must satisfy all of the following:

Rule Detail
Length 1–63 characters (PostgreSQL NAMEDATALEN − 1).
First character A letter (az, AZ) or an underscore (_).
Remaining characters Alphanumeric or underscore only. No hyphens, dots, spaces, or other symbols. ASCII only — Unicode letters are rejected.
Reserved names public, pg_catalog, information_schema, and pg_temp are rejected (case-insensitive).
Valid Invalid
tenant_123 tenant-123 (hyphen)
acme_corp 123abc (starts with a digit)
_private tenant.123 (dot)
production_api public (reserved)

An invalid name is rejected with a SchemaError (InvalidLength, InvalidStart, InvalidCharacters, or ReservedName). Tenant usernames follow the same rules, with their own reserved list of PostgreSQL role names (postgres, pg_*).

See Also