bria 0.1.4

Multi-pipeline job orchestrator
Documentation
# ─────────────────────────────────────────────────────────────────────────────
# Bria — Multi-pipeline job orchestrator
# Universal namespaced configuration (schema version 1)
# ─────────────────────────────────────────────────────────────────────────────
#
# Standalone usage:
#   bria --config Config.toml
#   BRIA_CONFIG=Config.toml bria
#
# For standalone Bria, a config may include only shared sections that Bria
# references plus the [bria] namespace. It is also valid to use this file as
# part of a merged universal config with shared profiles defined elsewhere.
#
# Environment variables:
#   ${VAR_NAME}         — required; load fails if unset
#   ${VAR_NAME:-default} — optional; uses default if unset
#
# Shared profile references (resolved at load time, not preserved at runtime):
#   store   = "<id>"  resolves [stores.<id>]
#   path_ref = "<id>"  resolves [paths.<id>]
#   transport = "<id>"  resolves [transports.<transport_kind>.<id>]
#
# See README.md for the full parameter reference.

version = 1

# ─── Shared root: logging (optional, inherited by [bria.global.log]) ─────────
[log]
level = "info"
format = "json"
file = ""

# ─── Shared root: runtime (optional, inherited by [bria.global]) ─────────────
[runtime]
worker_threads = 0
shutdown_timeout_secs = 30
tmp_dir = "data/tmp"
max_payload_bytes = 10485760

# ─── Shared root: HTTP defaults (optional, inherited by [bria.server]) ───────
[http]
bind = "0.0.0.0"
prefix = "v1"

# ─── Shared root: stores. Bria's state backend resolves from [stores.bria]. ──
#     SQLite is the default.  Postgres requires --features pg or --features postgres.
[stores.bria]
driver = "sqlite"
url = "sqlite://data/bria/bria-state.db"
migrate = true
connect_timeout_secs = 10
max_connections = 1

# ─── Shared root: path profiles for file sources/sinks ───────────────────────
[paths.bria_jobs]
kind = "file"
path = "data/bria/jobs/images.jsonl"
format = "jsonl"
create_parent_dirs = true

[paths.bria_results]
kind = "file"
path = "data/bria/results.jsonl"
format = "jsonl"
create_parent_dirs = true

# ─── Shared root: AMQP transport profile ────────────────────────────────────
[transports.amqp.local]
url = "amqp://localhost:5672"
reconnect_secs = 5
qos_prefetch = 100

# ─── Shared root: webhook transport profile ──────────────────────────────────
[transports.webhook.ops]
url = "${OPS_WEBHOOK_URL:-}"
method = "POST"
auth_scheme = "bearer"
token = "${OPS_WEBHOOK_TOKEN:-}"
timeout_secs = 10
max_retries = 3

# ══════════════════════════════════════════════════════════════════════════════
# BRI A NAMESPACE
# ══════════════════════════════════════════════════════════════════════════════

[bria]
enabled = true

# ─── Global defaults ──────────────────────────────────────────────────────────
[bria.global]
worker_threads = 0
shutdown_timeout_secs = 30
tmp_dir = "data/bria/tmp"
max_payload_bytes = 10485760
cancel_signal_ttl_secs = 3600

[bria.global.state]
backend = "sqlite"
store = "bria"        # resolves [stores.bria]
sqlite_path = "data/bria/bria-state.db"

[bria.global.retry]
max_attempts = 0
base_delay_ms = 1000
max_delay_ms = 30000
jitter = 0.2

[bria.global.timeout]
step_secs = 300
action = "term"
kill_grace_secs = 5

# ─── HTTP server (requires --features server) ─────────────────────────────────
[bria.server]
enabled = false
bind = "0.0.0.0"
port = 4000
prefix = "v1"
api_key = ""
dashboard_path_ref = ""   # optional, resolves [paths.<id>]
shutdown_timeout_secs = 5
max_body_bytes = 52428800

# ─── Sources ──────────────────────────────────────────────────────────────────
[[bria.sources]]
id = "image-file"
type = "file"
path_ref = "bria_jobs"   # resolves [paths.bria_jobs]
poll_interval_secs = 2
track_cursor = true
id_field = "job_id"
max_body_bytes = 1048576

[bria.sources.labels]
team = "ml-platform"
env = "local"

[[bria.sources]]
id = "image-http"
type = "http"
path = "jobs/images"
poll_interval_secs = 2
max_body_bytes = 1048576

[[bria.sources]]
id = "queue-jobs"
type = "queue"
enabled = false            # disabled example; requires --features amqp
transport = "local"        # resolves [transports.amqp.local]
exchange = "bria.jobs"
submit_routing_key = "job.submit"
cancel_routing_key = "job.cancel"
consumer_tag = "bria"

# ─── Tasks ────────────────────────────────────────────────────────────────────
[[bria.tasks]]
id = "add-red-balloon"
driver = "local"
cmd = "npx"
args = ["-y", "add-red-balloon", "{{job.payload.s3_url}}", "{{job.payload.prompt}}"]
inherit_env = false
success_exit_codes = [0]
timeout_secs = 300
timeout_action = "term"
kill_grace_secs = 5

[bria.tasks.env]
NODE_ENV = "production"

[bria.tasks.stdin]
mode = "none"

[bria.tasks.stdout]
mode = "capture"
max_bytes = 10485760

[bria.tasks.stderr]
mode = "capture"
max_bytes = 1048576

[bria.tasks.retry]
max_attempts = 3
base_delay_ms = 1000
max_delay_ms = 30000
jitter = 0.2

# ─── Sinks ────────────────────────────────────────────────────────────────────
[[bria.sinks]]
id = "results-file"
type = "file"
path_ref = "bria_results"   # resolves [paths.bria_results]
template = ""

[[bria.sinks]]
id = "results-webhook"
type = "webhook"
enabled = false              # requires --features webhook
transport = "ops"            # resolves [transports.webhook.ops]
template = ""

[[bria.sinks]]
id = "results-sqlite"
type = "sqlite"
store = "bria"               # resolves [stores.bria]
table_name = "pipeline_results"
path = "data/bria/results.db"
template = ""

[bria.sinks.db_table.columns]
result_id = "result_id"
job_id = "job_id"
pipeline_id = "pipeline_id"
step_id = "step_id"
occurred_at = "occurred_at"
exit_code = "exit_code"
stdout = "stdout"
stderr = "stderr"
duration_ms = "duration_ms"
attempt = "attempt"
status = "status"

# ─── Pipelines ────────────────────────────────────────────────────────────────
[[bria.pipelines]]
id = "image-pipeline"
source = "image-file"
concurrency = 4
queue_capacity = 1024
sinks = ["results-file"]

[bria.pipelines.failure]
action = "dead_letter"
sink = "results-file"

[[bria.pipelines.steps]]
id = "balloon"
type = "process"
task = "add-red-balloon"
depends_on = []
sinks = []

[bria.pipelines.steps.retry]
max_attempts = 3
base_delay_ms = 1000
max_delay_ms = 30000
jitter = 0.2