Configuration Reference
This page documents all configuration options for Milvaion API and Workers.
Milvaion API Configuration
appsettings.json Structure
{
"ConnectionStrings": {
"DefaultConnectionString": "Host=your_host;Port=5432;Database=MilvaionDb;Username=your_username;Password=your_password;Pooling=true;Minimum Pool Size=20;Maximum Pool Size=100;Connection Lifetime=900;Connection Idle Lifetime=180;Command Timeout=30;Include Error Detail=true"
},
"MilvaionConfig": {
"Logging": {
"Seq": {
"Enabled": true,
"Uri": "http://seq:5341"
}
},
"OpenTelemetry": {
"Service": "milvaion-backend",
"Environment": "milvaion-test",
"Job": "app-metrics",
"Instance": "milvaion-test",
"CollectorUrl": "http://grafana-alloy:4317"
},
"Redis": {
"ConnectionString": "redis:6379",
"Password": "",
"Database": 0,
"ConnectTimeout": 5000,
"SyncTimeout": 5000,
"KeyPrefix": "Milvaion:JobScheduler:",
"DefaultLockTtlSeconds": 600
},
"RabbitMQ": {
"Host": "rabbitmq",
"Port": 5672,
"Username": "guest",
"Password": "guest",
"VirtualHost": "/",
"Durable": true,
"AutoDelete": false,
"ConnectionTimeout": 30,
"Heartbeat": 60,
"AutomaticRecoveryEnabled": true,
"NetworkRecoveryInterval": 10,
"QueueDepthWarningThreshold": 100,
"QueueDepthCriticalThreshold": 500,
"ManagementEnabled": false,
"ManagementPort": 15672
},
"JobDispatcher": {
"Enabled": true,
"PollingIntervalSeconds": 1,
"BatchSize": 100,
"LockTtlSeconds": 600,
"EnableStartupRecovery": true,
},
"WorkerAutoDiscovery": {
"Enabled": true
},
"ZombieOccurrenceDetector": {
"Enabled": true,
"CheckIntervalSeconds": 300,
"ZombieTimeoutMinutes": 10
},
"LogCollector": {
"Enabled": true,
"BatchSize": 100,
"BatchIntervalMs": 1000
},
"StatusTracker": {
"Enabled": true,
"BatchSize": 50,
"BatchIntervalMs": 100,
"ExecutionLogMaxCount": 100
},
"FailedOccurrenceHandler": {
"Enabled": true
},
"JobAutoDisable": {
"Enabled": true,
"ConsecutiveFailureThreshold": 5,
"FailureWindowMinutes": 60,
"AutoReEnableAfterCooldown": false,
"AutoReEnableCooldownMinutes": 30
},
"WorkflowEngine": {
"Enabled": true,
"PollingIntervalSeconds": 5
}
}
}
Connection Strings
| Setting | Description |
|---|---|
DefaultConnectionString | PostgreSQL connection string |
OpenTelemetry
Open telemetry configurations. Set null or empty via environment variables if you don't want export telemetry.
Redis Configuration
| Setting | Default | Description |
|---|---|---|
ConnectionString | localhost:6379 | Redis server address |
Password | "" | Redis password (if auth enabled) |
Database | 0 | Redis database index (0-15) |
ConnectTimeout | 5000 | Connection timeout in milliseconds |
SyncTimeout | 0 | Sync timeout for Redis operations in milliseconds. |
KeyPrefix | 0 | Key prefix for job scheduler keys (e.g. "Milvaion:JobScheduler:"). |
DefaultLockTtlSeconds | 0 | Default lock TTL in seconds. |
RabbitMQ Configuration
| Setting | Default | Description |
|---|---|---|
Host | localhost | RabbitMQ server hostname |
Port | 5672 | AMQP port |
Username | guest | RabbitMQ username |
Password | guest | RabbitMQ password |
VirtualHost | / | Virtual host name |
Durable | / | Whether the queue should be durable (survives broker restart). |
AutoDelete | / | Whether the queue should auto-delete when no consumers. |
ConnectionTimeout | / | Connection timeout in seconds. |
Heartbeat | / | Heartbeat interval in seconds (0 = disabled). |
AutomaticRecoveryEnabled | / | Automatic connection recovery enabled. |
NetworkRecoveryInterval | / | Network recovery interval in seconds. |
QueueDepthWarningThreshold | 5000 | Message count that triggers a Warning health status. |
QueueDepthCriticalThreshold | 10000 | Message count that triggers a Critical health status. |
ManagementEnabled | false | Enable RabbitMQ Management HTTP API integration for richer queue stats and dynamic queue discovery. |
ManagementPort | 15672 | RabbitMQ Management plugin HTTP port. Used when ManagementEnabled is true. |
Job Dispatcher Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable/disable job dispatching |
PollingIntervalSeconds | 1 | How often to check for due jobs |
BatchSize | 100 | Max jobs to dispatch per poll |
LockTtlSeconds | 600 | Distributed lock TTL (10 min) |
EnableStartupRecovery | true | Whether to perform zombie job recovery on startup. Default: true. |
Worker Auto Discovery Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable worker auto discovery |
Zombie Detector Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable zombie job detection |
CheckIntervalSeconds | 300 | Interval (in seconds) between zombie detection checks. Default: 300 seconds (5 minutes). |
ZombieTimeoutMinutes | 10 | Timeout (in minutes) before marking a Running/Queued occurrence as zombie. Running jobs that don't update heartbeat for this duration are marked as Unknown. Default: 10 minutes |
Log Collector Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable log collection. |
BatchSize | 100 | Batch size for processing log entries. |
BatchIntervalMs | 1000 | Interval in milliseconds between processing batches. |
Status Tracker Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable status tracking |
BatchSize | 50 | Batch size for processing status updates. |
BatchIntervalMs | 100 | Interval in milliseconds between processing batches. |
ExecutionLogMaxCount | 100 | Maximum number of execution log entries to keep per job occurrence. |
Failed Occurrence Handler Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable failed occurrence handling |
Job Auto Disable Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable auto-disable jobs on consecutive failures |
ConsecutiveFailureThreshold | 5 | Number of consecutive failures before a job is automatically disabled. Individual jobs can override this with their own AutoDisableThreshold setting. Default: 5 consecutive failures |
FailureWindowMinutes | 60 | Time window in minutes for counting consecutive failures. Failures older than this window don't count towards the threshold. This prevents jobs from being disabled due to old historical failures. Default: 60 minutes (1 hour) |
Workflow Engine Configuration
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable workflow engine background service. When enabled, the engine polls for workflow runs and executes ready steps. |
PollingIntervalSeconds | 5 | How often (in seconds) the workflow engine polls for ready steps to execute. Lower values provide faster step transitions but increase database load. |
BasePath Configuration
Milvaion API supports hosting under a configurable sub-path (e.g. /milvaion) so that both the UI and the backend API can be scoped to a URL prefix. This is useful when deploying behind a reverse proxy alongside other services.
| Setting | Default | Description |
|---|---|---|
BasePath | "" | URL prefix the application is mounted under. Leave empty to host at the root. Example: /milvaion |
When BasePath is set:
- The REST API is available at
{BasePath}/api/v1/...(e.g./milvaion/api/v1/jobs) - The SignalR hub is available at
{BasePath}/hubs/jobs - The Prometheus metrics endpoint is available at
{BasePath}/metrics - The Scalar/OpenAPI documentation is available at
{BasePath}/scalar/v1 - The SPA (UI) is served at
{BasePath}and all sub-routes fall back to the SPA index
When BasePath is empty or not set, the application is hosted at the root (/).
Example Configuration
{
"MilvaionConfig": {
"BasePath": "/milvaion"
}
}
Environment Variable Override
MilvaionConfig__BasePath=/milvaion
Docker / docker-compose
services:
milvaion-api:
image: milvasoft/milvaion:latest # pull from Docker Hub, no rebuild needed
environment:
- MilvaionConfig__BasePath=/milvaion
To revert to root hosting, remove the override or set it to empty:
environment:
- MilvaionConfig__BasePath=
Frontend Environment Variables
The frontend SPA must be built with the matching base path so that Vite asset URLs, React Router navigation, and API/SignalR client URLs align with the backend.
| Variable | Default | Description |
|---|---|---|
VITE_BASE_PATH | / | URL prefix baked into the frontend bundle at build time. Must match MilvaionConfig:BasePath. |
# .env.production
VITE_BASE_PATH=/milvaion
Note: Changing
BasePathrequires rebuilding the frontend bundle because the value is baked in at build time. If you change it at runtime on the backend only, the SPA asset references and client-side navigation will break.
Worker Configuration
Worker appsettings.json Structure
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Debug",
"System": "Debug"
}
},
"Worker": {
"WorkerId": "sample-worker-01",
"MaxParallelJobs": 128,
"MaxParallelJobsPerWorker": 128,
"ExecutionTimeoutSeconds": 300,
"RabbitMQ": {
"Host": "rabbitmq",
"Port": 5672,
"Username": "guest",
"Password": "guest",
"VirtualHost": "/"
},
"Redis": {
"ConnectionString": "redis:6379",
"Password": "",
"Database": 0,
"CancellationChannel": "Milvaion:JobScheduler:cancellation_channel"
},
"Heartbeat": {
"Enabled": true,
"IntervalSeconds": 5,
"JobHeartbeatIntervalSeconds": 60
},
"OfflineResilience": {
"Enabled": true,
"LocalStoragePath": "./worker_data",
"SyncIntervalSeconds": 30,
"MaxSyncRetries": 3,
"CleanupIntervalHours": 1,
"RecordRetentionDays": 1
}
},
"JobConsumers": {
"SimpleJob": {
"ConsumerId": "simple-consumer",
"MaxParallelJobs": 32,
"MaxParallelJobsPerWorker": 128,
"ExecutionTimeoutSeconds": 120,
"MaxRetries": 3,
"BaseRetryDelaySeconds": 5,
"LogUserFriendlyLogsViaLogger": true
},
"SendEmailJob": {
"ConsumerId": "email-consumer",
"MaxParallelJobs": 16,
"MaxParallelJobsPerWorker": 128,
"ExecutionTimeoutSeconds": 600,
"MaxRetries": 3,
"BaseRetryDelaySeconds": 5,
"LogUserFriendlyLogsViaLogger": true
}
}
}
Worker Core Settings
| Setting | Default | Required | Description |
|---|---|---|---|
WorkerId | - | Yes | Unique identifier for this worker (app-level, user-defined). Example: "sample-worker", "email-worker". Same across all replicas/instances. |
MaxParallelJobs | 10 | No | Maximum parallel jobs this instance can run simultaneously. Default: ProcessorCount * 2 (e.g., 8 cores = 16 parallel jobs). |
ExecutionTimeoutSeconds | 3600 | No | Default maximum execution time allowed for jobs (in seconds). If a job exceeds this timeout, it will be cancelled and marked as TimedOut. Default: 3600 seconds (1 hour). Set to 0 or negative value for no timeout (not recommended). Can be overridden per job consumer in JobConsumerOptions. |
Worker RabbitMQ Settings
| Setting | Default | Description |
|---|---|---|
Host | localhost | RabbitMQ server |
Port | 5672 | AMQP port |
Username | guest | Username |
Password | guest | Password |
VirtualHost | / | Virtual host |
RoutingKeyPattern | # | Queue binding pattern. Don't recommended setting up routing patterns. The scheduler and worker will determine this automatically at runtime. |
Worker Redis Settings
| Setting | Default | Description |
|---|---|---|
ConnectionString | localhost:6379 | Redis server |
Password | "" | Redis password |
Database | 0 | Redis database index |
CancellationChannel | Milvaion:JobScheduler:cancellation_channel | Redis pub/sub cancellation channel. If you change this value you must change in scheduler config too. |
Heartbeat Settings
| Setting | Default | Description |
|---|---|---|
Enabled | true | Send heartbeats to Redis |
IntervalSeconds | 10 | Heartbeat frequency |
JobHeartbeatIntervalSeconds | 10 | Job heartbeat interval in seconds (for zombie detection). Should be less than ZombieTimeoutMinutes to prevent false positives. Default: 60 seconds. |
Offline Resilience Settings
| Setting | Default | Description |
|---|---|---|
Enabled | true | Enable local SQLite fallback |
LocalStoragePath | ./worker_data | SQLite database location |
SyncIntervalSeconds | 30 | Interval (in seconds) for syncing pending items to scheduler. Default: 30 seconds |
MaxSyncRetries | 3 | Maximum number of retry attempts for failed sync operations. After max retries, items are marked as synced to prevent blocking. Default: 3 |
CleanupIntervalHours | 1 | Interval (in hours) for cleaning up old synced records. Default: 1 hours |
RecordRetentionDays | 1 | Retention period (in days) for synced records before cleanup. Default: 1 days |