Server Configuration¶
The server is configured via environment variables and CLI flags. CLI flags take priority over environment variables, which take priority over defaults.
Configuration Methods¶
1. Environment Variables (.env.secret file)¶
Create a .env.secret file in the parent directory of app/:
# .env.secret
RUNQY_API_KEY=your-secret-api-key
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your-redis-password
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=your-db-password
DATABASE_DBNAME=sdxl_queuing_dev
2. CLI Flags¶
runqy serve --port 8080 --api-key my-key --redis-uri redis://:password@localhost:6379
runqy serve --db-host pg.example.com --db-name mydb --db-user admin
runqy serve --sqlite --sqlite-path ./data/runqy.db
3. Priority Order¶
Environment Variables Reference¶
Server¶
| Variable | Default | CLI Flag | Description |
|---|---|---|---|
PORT |
3000 |
--port |
HTTP server port |
RUNQY_API_KEY |
— | --api-key (global) |
API key for authenticated endpoints |
Redis¶
| Variable | Default | CLI Flag | Description |
|---|---|---|---|
REDIS_HOST |
localhost |
— | Redis hostname |
REDIS_PORT |
6379 |
— | Redis port |
REDIS_PASSWORD |
— | — | Redis password |
REDIS_TLS |
false |
--redis-tls |
Enable TLS for Redis connection |
| — | — | --redis-uri (global) |
Redis URI (overrides host/port/password/tls). Format: redis[s]://[:password@]host[:port] |
PostgreSQL¶
| Variable | Default | CLI Flag | Description |
|---|---|---|---|
DATABASE_HOST |
localhost |
--db-host |
PostgreSQL hostname |
DATABASE_PORT |
5432 |
--db-port |
PostgreSQL port |
DATABASE_USER |
postgres |
--db-user |
PostgreSQL username |
DATABASE_PASSWORD |
— | --db-password |
PostgreSQL password |
DATABASE_DBNAME |
sdxl_queuing_dev |
--db-name |
PostgreSQL database name |
DATABASE_SSL |
disable |
--db-ssl |
PostgreSQL SSL mode |
SQLite (alternative to PostgreSQL)¶
| Variable | Default | CLI Flag | Description |
|---|---|---|---|
SQLITE_DB_PATH |
runqy.db |
--sqlite-path |
SQLite database file path |
| — | — | --sqlite |
Use SQLite instead of PostgreSQL |
Monitoring & Security¶
| Variable | Default | CLI Flag | Description |
|---|---|---|---|
ASYNQ_READ_ONLY |
false |
— | Restrict monitoring UI to read-only mode |
PROMETHEUS_ADDRESS |
— | — | Prometheus server URL for time-series charts |
RUNQY_JWT_SECRET |
(auto-generated) | — | JWT secret for dashboard authentication. If not set, a random secret is generated on each restart (sessions won't survive restarts) |
RUNQY_VAULT_MASTER_KEY |
— | — | Base64-encoded 32-byte key for vault encryption. If not set, the vaults feature is disabled |
Additional Server Flags¶
| Flag | Description |
|---|---|
--config <dir> |
Path to queue workers config directory (overrides QUEUE_WORKERS_DIR) |
--watch |
Enable file/git watching for config auto-reload |
--config-repo <url> |
GitHub repo URL for configs |
--config-branch <branch> |
Git branch (default: main) |
--no-ui |
Disable the monitoring web dashboard |
--debug |
Enable verbose logging |
Queue Worker Definitions (YAML)¶
Optional
YAML-based queue definitions are optional. In most cases, queues are created and managed after startup using the CLI (runqy config create) or the monitoring dashboard GUI.
YAML files in the deployment/ directory (or a custom directory specified with --config) allow you to pre-configure queues so that a fresh server starts with all queues already set up — useful for automated deployments or spinning up new environments.
queues:
inference:
priority: 6
mode: long_running # or one_shot
deployment:
git_url: "https://github.com/example/repo.git"
branch: "main"
startup_cmd: "python main.py"
startup_timeout_secs: 300
requirements_file: "requirements.txt" # Optional
simple:
priority: 3
mode: one_shot
deployment:
git_url: "https://github.com/example/simple-tasks.git"
branch: "main"
startup_cmd: "python task.py"
startup_timeout_secs: 60
Queue Options¶
| Option | Type | Required | Description |
|---|---|---|---|
priority |
int | Yes | Queue priority (higher = more important) |
mode |
string | No | Execution mode: long_running (default) or one_shot |
deployment |
object | Yes | Deployment configuration |
Deployment Options¶
| Option | Type | Required | Description |
|---|---|---|---|
git_url |
string | Yes | Git repository URL for task code |
branch |
string | Yes | Git branch to clone |
code_path |
string | No | Path of the task code within the repository (e.g., simple-task) |
startup_cmd |
string | Yes | Command to start the Python process |
startup_timeout_secs |
int | Yes | Timeout for process startup |
requirements_file |
string | No | Path to requirements.txt (default: requirements.txt) |
vaults |
list | No | List of vault names to inject as environment variables |
redis_storage |
bool | No | If true, task results are written to Redis. If false, results are not stored in Redis and must be managed by the task itself (e.g., via webhook). Default: false |
git_token |
string | No | Path to your github PAT's. Use the following format vault://{VAULT-NAME}/{KEY} (e.g., vault://github_pats/SIMPLE_TASK) |
Sub-Queues¶
Sub-queues allow you to assign different priorities to the same task type based on the caller's tier or urgency. This is useful when multiple clients submit identical tasks but require different service levels.
Use Case: Paid vs Free Users¶
A common pattern is routing tasks from paid users to a high-priority sub-queue while free users go to a lower-priority sub-queue:
queues:
inference:
sub_queues:
- name: premium # Paid users — processed first
priority: 10
- name: standard # Free users — processed when premium queue is empty
priority: 3
deployment:
git_url: "https://github.com/example/inference.git"
branch: "main"
startup_cmd: "python main.py"
startup_timeout_secs: 300
Your API backend then routes tasks based on user tier:
# In your API backend
if user.is_premium:
client.enqueue("inference.premium", payload)
else:
client.enqueue("inference.standard", payload)
Both sub-queues run the same task code (same deployment), but workers prioritize inference.premium tasks over inference.standard tasks.
Naming Format¶
Queues use the format {parent}.{sub_queue}:
inference.premium— High priority inference tasksinference.standard— Standard priority inference taskssimple.default— Default simple tasks
Workers register for a parent queue and can process tasks from any of its sub-queues based on priority.
Queue Creation Behavior¶
When you define a queue in the configuration, the sub-queues created depend on whether you explicitly define them:
| Configuration | Sub-queues created |
|---|---|
No sub_queues defined |
.default is created automatically |
sub_queues explicitly defined |
Only the listed sub-queues are created (NO .default) |
Example 1: No sub-queues → .default is created
Example 2: Explicit sub-queues → only those are created
queues:
myqueue:
sub_queues:
- name: high
priority: 10
- name: low
priority: 3
deployment: ...
# Creates: myqueue.high, myqueue.low
# Does NOT create: myqueue.default
Fallback to .default may fail
If you reference myqueue (without sub-queue suffix) and .default doesn't exist (because you defined explicit sub-queues), the operation will fail. Always use the full queue name when sub-queues are explicitly defined.
Automatic Default Fallback¶
When a queue name is referenced without a sub-queue suffix, runqy automatically appends .default:
| You provide | Resolves to |
|---|---|
inference |
inference.default |
simple |
simple.default |
inference.high |
inference.high (unchanged) |
This applies to:
- Workers: When a worker registers for queue
inference, it actually registers forinference.default - Task enqueueing: When you enqueue a task to
inference, it goes toinference.default - Task retrieval: When you query queue
inference, it looks upinference.default
Queue must exist
If the resolved queue (e.g., inference.default) doesn't exist in the configuration, an error is returned. The fallback only adds the .default suffix—it doesn't create the queue automatically.
Monitoring¶
Environment Variables¶
| Variable | Required | Description |
|---|---|---|
PROMETHEUS_ADDRESS |
No | Prometheus server URL (e.g., http://localhost:9090). Enables time-series charts in the dashboard. If not set, the dashboard uses Redis-based historical data. |
The server always exposes Prometheus metrics at /metrics regardless of this setting. See the Monitoring Guide for full setup instructions including dashboard authentication.
Vaults¶
Vaults provide secure storage for secrets that are injected into workers as environment variables.
Environment Variables¶
| Variable | Required | Description |
|---|---|---|
RUNQY_VAULT_MASTER_KEY |
No | Base64-encoded 32-byte key for encrypting vault entries. If not set, the vaults feature is disabled. |
Generating a Master Key¶
# Generate a secure 256-bit key
openssl rand -base64 32
# Output: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
# Set as environment variable
export RUNQY_VAULT_MASTER_KEY="YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY="
Using Vaults in Queue Configuration¶
queues:
inference:
priority: 6
deployment:
git_url: "https://github.com/example/repo.git"
branch: "main"
startup_cmd: "python main.py"
startup_timeout_secs: 300
vaults:
- api-keys
- model-credentials
When a worker registers for this queue, all entries from the specified vaults are decrypted and sent to the worker. The worker then injects them as environment variables before starting the Python process.
Accessing Secrets in Python¶
import os
# Access vault entries as environment variables
openai_key = os.environ.get("OPENAI_API_KEY")
hf_token = os.environ.get("HF_TOKEN")
Security Note
Vault entries are transmitted to workers during bootstrap. Ensure workers are running in a trusted environment and the connection to the server is secured (HTTPS).