Run locally

Ursula's HTTP server is the ursula binary. It takes its configuration from CLI flags and a small set of environment variables - there is no config file yet.

Default (in-process, non-replicated)

With no storage flag, Ursula runs an in-process non-replicated default runtime (no Raft at all). Nothing is persisted. Best for state-machine smoke tests and first-impression testing:

cargo run --bin ursula

It binds 127.0.0.1:4437, picks a core count from your CPU, and uses the in-memory engine.

In-memory Raft

OpenRaft with an in-memory log. Fast iteration, no persistence, but the runtime exercises the real Raft path:

cargo run --bin ursula -- --storage-backend memory

Disk-backed single node

Persistent local storage. Streams survive a restart:

cargo run --bin ursula -- --storage-backend disk --disk-path ./data

The --disk-path directory will contain a raft-log/ subdirectory with protobuf-framed Raft log records per group plus a shared journal.bin per core. Removing the directory wipes state cleanly.

Smoke test

curl -X PUT http://127.0.0.1:4437/demo
curl -X PUT http://127.0.0.1:4437/demo/hello

curl -X POST http://127.0.0.1:4437/demo/hello \
  -H 'Content-Type: application/octet-stream' \
  --data-binary 'hello'

curl 'http://127.0.0.1:4437/demo/hello?offset=-1'

Inspect runtime metrics (placement, mailbox depth, per-core counters):

curl http://127.0.0.1:4437/__ursula/metrics | jq .

Flags

FlagDefaultNotes
--listen ADDR127.0.0.1:4437TCP bind address
--core-count Navailable_parallelismWorker threads (each pinned to its mailbox event loop)
--raft-group-count Ncore_count × 16Total Raft groups. Higher = better stream-to-group hash spread
--storage-backend BACKENDdefault runtimememory or disk
--disk-path DIRnoneRequired for disk; Raft logs live under DIR/raft-log
--raft-node-id IDnoneRequired for static gRPC cluster mode
--raft-peer ID=URLnone (repeatable)Static peer list for the cluster
--raft-cluster-config FILEnoneJSON file equivalent of --raft-node-id + --raft-peer
--raft-init-membership[-per-group]offOne-time membership bootstrap

--storage-backend disk uses the durable OpenRaft log store. Static gRPC clusters use the same disk backend or memory for volatile tests.

Environment variables

A small set of knobs are read at startup:

  • URSULA_LIVE_READ_MAX_WAITERS_PER_CORE (default 65536) - SSE waiter cap per core
  • URSULA_COLD_MAX_HOT_BYTES_PER_GROUP (default 64 MiB) - when a group's hot ring exceeds this, cold flush kicks in
  • URSULA_COLD_BACKEND (memory or s3), URSULA_COLD_S3_*, URSULA_COLD_ROOT, URSULA_COLD_FLUSH_* - cold-storage configuration. See configure S3
  • URSULA_TOKIO_CONSOLE - when set, initializes the Tokio console subscriber (requires building with --features tokio-console and RUSTFLAGS="--cfg tokio_unstable")

Next