Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Deployment & Operations

This chapter covers building, deploying, and operating Umari in production.

Building modules

The umari CLI builds every module in the workspace, in either language, and handles the wasm32-wasip2 (Rust) or componentize (TypeScript) build for you.

Prerequisites

rustup target add wasm32-wasip2

Building

umari build                          # build every module in the workspace
umari build commands/create-project  # build a single module
umari build --debug                  # debug profile

umari deploy runs the same build and then uploads and activates each module. See Project Structure for the full CLI.

Versioning

Each module has a version that the runtime uses for lifecycle management. Increment it when you make changes; the runtime tracks versions and supports rolling upgrades, where activating a new version stops the old one gracefully.

Set the version in the module’s Cargo.toml:

[package]
name = "register-user"
version = "1.0.18"

Starting the server

Binary

umari \
  --data-dir ./umari-data \
  --event-store-url http://umadb:50051 \
  --api-addr 0.0.0.0:3000

Environment variables

VariableDefaultDescription
UMARI_DATA_DIR./umari-dataData directory for SQLite, cache
UMARI_EVENT_STORE_URLhttp://localhost:50051UmaDB gRPC endpoint
UMARI_API_ADDR127.0.0.1:3000API server bind address
UMARI_API_KEY(none)API key for authentication
UMARI_LOGumari=infoLog filter (env_logger format)
UMARI_NO_BANNER(unset)Set to any value to hide startup banner
UMARI_VERBOSE(unset)Set to any value for trace-level logging
UMARI_METRICS_INTERVAL15sHow often to refresh state-derived metrics; 0 disables the collector. See Monitoring & Alerting
UMARI_SHUTDOWN_TIMEOUT10sGraceful shutdown timeout

Security

Set UMARI_API_KEY in production. Without it, the API is unauthenticated.

export UMARI_API_KEY="your-secret-key"

The API requires Authorization: Bearer your-secret-key on all requests. The Web UI uses cookie-based auth with the same key.

Deploying modules

Most of the time you’ll use umari deploy, which builds every module in the workspace, uploads it, and activates it in one step. The commands below are the lower-level operations it’s built on. Each module type has its own subcommand group: commands, projectors, and effects.

Via CLI

# Upload a version (name, version, then the wasm file)
umari commands upload register-user 1.0.18 ./register_user.wasm

# Upload and activate in one step
umari commands upload register-user 1.0.18 ./register_user.wasm --activate

# Activate a previously uploaded version
umari commands activate register-user 1.0.18

# List active modules
umari modules active

# Execute a command (input is passed with --input)
umari execute register-user --input '{"user_id": 42, "email": "user@example.com"}'

Via API

# Upload a version (the wasm file goes in a multipart "wasm" field)
curl -X POST "http://localhost:3000/commands/register-user/versions/1.0.18" \
  -H "Authorization: Bearer $UMARI_API_KEY" \
  -F "wasm=@register_user.wasm"

# Activate a version
curl -X PUT http://localhost:3000/commands/register-user/active \
  -H "Authorization: Bearer $UMARI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"version": "1.0.18"}'

# Execute a command (the request body is the input JSON itself)
curl -X POST http://localhost:3000/commands/register-user/execute \
  -H "Authorization: Bearer $UMARI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id": 42, "email": "user@example.com"}'

To make a command idempotent, send a client-generated idempotency-key header on execute; the runtime skips execution if an event carrying that key already exists. The projector and effect groups use the same routes under /projectors/{name} and /effects/{name}.

Environment variables for modules

Modules read environment variables through the SDK (env::var in Rust, env() in TypeScript; see Effects). Set them per-module:

# Via CLI
umari effects env register-webhooks set WEBHOOK_ADDRESS "https://webhook.example.com"

# Via API (the key is in the path, the value in the body)
curl -X PUT http://localhost:3000/effects/register-webhooks/env/WEBHOOK_ADDRESS \
  -H "Authorization: Bearer $UMARI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value": "https://webhook.example.com"}'

Modules can also ship default env values that apply on upload:

Declare them in the module’s Cargo.toml, and umari deploy picks them up automatically:

[package.metadata.umari.env]
WEBHOOK_ADDRESS = "https://webhook.example.com"

Operating

Checking health

GET /commands/active
GET /projectors/active
GET /effects/active

Each returns the active modules of that type along with their liveness and, for projectors and effects, their committed last_position. For numeric metrics and alerting, see Monitoring & Alerting.

Replaying

POST /projectors/{name}/replay
POST /effects/{name}/replay

Deletes the SQLite database and reprocesses all events from the beginning. Use for schema changes or recovery.

Compaction

The event store (UmaDB) should be compacted periodically to reclaim space from deleted or overwritten events. Refer to the UmaDB documentation for compaction procedures.

Backups

What to back up

  • UmaDB event store: the source of truth. Everything else is derivable.
  • umari.sqlite: module store (WASM bytes, crypto keys, metadata). Without this, you’d need to re-upload all modules.
  • Module source code: WASM bytes in the store are binary; keep source in git.

What NOT to back up

  • Projector/effect SQLite databases: these are derivable from events via replay.
  • cache/*.cwasm: compiled cache, regenerated on restart.

Production checklist

  • UMARI_API_KEY is set
  • UmaDB is running and accessible
  • Modules are built with --release
  • Env vars are set for all effects
  • Data directory has sufficient disk space (event store grows indefinitely)
  • Logging is configured (UMARI_LOG)
  • Backup strategy is in place for UmaDB and umari.sqlite
  • Monitoring and alerting are set up (metrics scrape, dashboard, alerts)