Chuyển tới nội dung chính

Deployment

A Riverbase service is one static binary plus Postgres. Optionally it also needs a message broker (NATS or Redis) and an identity provider.

Service modes​

One process serves command and query routes for its domains. This is the right default: one deployment, one pool, and reads immediately see the process's own writes.

app.mount_domain(domain).await?;   // commands + queries + custom routes

Migrations at boot​

Every service binary should support --migrate-only:

let runtime = DomainRuntime::from_config(app.config()).await?;          // framework migrations
let domain = TodoDomain::<PgDataStore>::spawn(&runtime).await?.into_arc(); // domain migrations
if RiverbaseApp::migrate_only() {
return Ok(());
}

Run it as a one-off job (a Kubernetes Job, an init container, or a release phase) before rolling out new replicas. Each crate tracks its own migrations in its own schema, so the framework, the extension crates, and your domains migrate independently.

Container image​

Dockerfile
FROM rust:1.83-bookworm AS build
WORKDIR /src
COPY . .
RUN cargo build --release -p todo-service

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates libpq5 && rm -rf /var/lib/apt/lists/*
COPY --from=build /src/target/release/todo-service /usr/local/bin/todo-service
ENV RIVERBASE_BIND_ADDR=0.0.0.0:8080 RIVERBASE_LOG_FORMAT=json
EXPOSE 8080
ENTRYPOINT ["todo-service"]

The image needs libpq for Diesel's Postgres driver. Pass configuration through RIVERBASE_* variables or mount a riverbase.toml and point RIVERBASE_CONFIG at it.

What runs alongside​

ComponentNeeded whenNotes
PostgreSQL 14+AlwaysState, audit, outbox, tracker, and extension tables
NATSProduction messaging (the default bus)Or Redis, or Postgres LISTEN/NOTIFY for small setups
Keycloak or another OIDC IdPAuthenticated APIsRiverbase validates tokens; it does not store users
Workers (riverbase_task)Post-commit side effectsScale independently of the API

Scaling notes​

  • Replicas: API replicas are stateless. Sessions are signed cookies, and realtime fan-out goes through the StreamBus.
  • Pool sizing: dbpool_max_size (default 32) multiplied by the replica count must fit Postgres's max_connections, leaving room for workers and migrations.
  • Command concurrency: command_pool_size limits in-flight commands per engine and process. Raise it for I/O-heavy handlers, but remember that correctness comes from the database, not the pool.
  • Outbox: every replica runs a publisher. Rows are claimed with FOR UPDATE SKIP LOCKED, so replicas do not pick up the same row at once. Delivery is still at least once, so consumers must be idempotent.

Health​

Expose a liveness route, either a domain! routes probe or a public route registered with a reason. RiverbaseApp also tracks migration readiness (mark_migrations_ready, readiness()) for a readiness probe.