pub struct DatabaseConfig {Show 24 fields
pub url: Option<String>,
pub primary_url: Option<String>,
pub replica_url: Option<String>,
pub pool_size: usize,
pub primary_pool_size: Option<usize>,
pub replica_pool_size: Option<usize>,
pub replica_fallback: ReplicaFallback,
pub read_your_writes: ReadYourWrites,
pub pin_after_write_secs: u64,
pub replica_max_lag_ms: Option<u64>,
pub warn_on_pooler: bool,
pub connect_timeout_secs: u64,
pub startup_wait_secs: u64,
pub auto_migrate: Option<bool>,
pub auto_migrate_in_production: bool,
pub statement_timeout: Option<Duration>,
pub idle_in_transaction_timeout: Option<Duration>,
pub migration_lock_timeout: Duration,
pub migration_lock_retries: u32,
pub slow_query_threshold: Duration,
pub shards: Vec<ShardConfig>,
pub directory_shard_router: bool,
pub max_connections_warn_threshold: usize,
pub fleet: Option<DatabaseFleetConfig>,
}Expand description
Database connection configuration.
When url is None (the default), the application runs without a
database – useful for static-site or API-gateway use cases. Set a
Postgres URL to enable the connection pool and the Db
extractor.
§Defaults
| Field | Default |
|---|---|
url | None |
primary_url | None |
replica_url | None |
pool_size | 10 |
primary_pool_size | None |
replica_pool_size | None |
replica_fallback | fail_readiness |
connect_timeout_secs | 5 |
auto_migrate | None |
auto_migrate_in_production | false |
shards | [] |
§Examples
use autumn_web::config::DatabaseConfig;
let db = DatabaseConfig::default();
assert!(db.url.is_none());
assert_eq!(db.pool_size, 10);Fields§
§url: Option<String>Postgres connection URL. None means no database is configured.
Compatibility alias for the primary/write role. New multi-role
deployments should prefer primary_url.
When present, must start with postgres:// or postgresql://, or be
a libpq-style keyword/value connection string
(host=db user=app dbname=app sslmode=require).
primary_url: Option<String>Postgres URL for the primary/write role.
All writes, transactions, advisory locks, and migrations use this role.
When unset, url remains the single-primary fallback.
replica_url: Option<String>Optional Postgres URL for the read/replica role.
Read-only paths may use this pool when configured. If omitted, read paths use the primary role.
pool_size: usizeMaximum number of connections in the pool. Default: 10.
Compatibility/default pool size used for both roles unless a role-specific size is set.
primary_pool_size: Option<usize>Optional primary/write role pool size.
replica_pool_size: Option<usize>Optional read/replica role pool size.
replica_fallback: ReplicaFallbackDeterministic behavior for configured replicas that cannot safely serve reads. Default: fail readiness.
read_your_writes: ReadYourWritesPost-write read pinning strategy. Default: off (no pinning).
Set to request to pin reads to the primary for the remainder of the
request after the first write. Set to session to additionally pin
reads across requests via a signed cookie.
Override via AUTUMN_DATABASE__READ_YOUR_WRITES.
pin_after_write_secs: u64Duration (seconds) for cross-request session pins.
Only used when read_your_writes = "session". A signed autumn.ryw
cookie pins the client’s reads to the primary for this many seconds
after a write. Default: 5.
Override via AUTUMN_DATABASE__PIN_AFTER_WRITE_SECS.
replica_max_lag_ms: Option<u64>Maximum replica lag, in milliseconds (issue #3065).
When set, the app measures the replica lag in the background, and
/ready reports the last sample. While the lag is over the limit, or
not known, reads go to
the primary. Lag alone does not fail readiness. None or 0 turns
the check off. Override via AUTUMN_DATABASE__REPLICA_MAX_LAG_MS.
warn_on_pooler: boolLog a warning at boot when a database URL looks like a connection
pooler (PgBouncer, RDS Proxy, Supavisor, Neon). Default: true.
See docs/guide/connection-poolers.md. Override via
AUTUMN_DATABASE__WARN_ON_POOLER.
connect_timeout_secs: u64Seconds to wait while acquiring a pooled connection, including
creating a new connection when the pool grows.
Default: 5.
startup_wait_secs: u64Bounded startup wait (seconds) for the database to become reachable
before the migrator fails. 0 (the default) disables the wait and
preserves the current fail-fast behaviour — a single connection attempt,
no retry. Set a non-zero value (e.g. 60) to have autumn migrate
retry with capped exponential backoff until either the database accepts
connections or the window elapses.
Override via AUTUMN_DATABASE__STARTUP_WAIT_SECS.
auto_migrate: Option<bool>Profile-agnostic explicit override for startup migration auto-apply
(issue #1903). None (the default, when the key is absent) leaves the
decision to convention: dev/development auto-apply, every other
profile (prod/production and custom names like fly/staging)
is opt-in. Some(true) / Some(false) overrides that convention on
any profile.
This supersedes Self::auto_migrate_in_production, which is retained
as a back-compat alias: when auto_migrate is unset but
auto_migrate_in_production = true, auto-apply is enabled on any
non-dev profile (so a custom-profile operator’s existing config finally
takes effect). auto_migrate wins when both are set.
Override via AUTUMN_DATABASE__AUTO_MIGRATE.
auto_migrate_in_production: boolBack-compat alias for Self::auto_migrate (issue #1903). When true,
permits automatic migration application on any non-dev profile (not
just prod/production — the old name-gated behavior silently skipped
custom profiles). Default: false. Prefer setting auto_migrate
directly; this key is honored only when auto_migrate is unset.
Keep this disabled for multi-replica production fleets and use an
explicit migration job (autumn migrate) instead.
statement_timeout: Option<Duration>Optional database statement timeout. "0s" disables it.
Set as a session SET on checkout, and again as SET LOCAL at the
start of each framework transaction, so a transaction pooler such as
PgBouncer cannot drop it. The prod profile sets 30s (#3057).
Override via AUTUMN_DATABASE__STATEMENT_TIMEOUT.
idle_in_transaction_timeout: Option<Duration>Optional idle_in_transaction_session_timeout. "0s" disables it.
Set as SET LOCAL at the start of each framework transaction. Postgres
ends a session that stays idle in an open transaction for longer than
this. The prod profile sets 60s (#3057).
Override via AUTUMN_DATABASE__IDLE_IN_TRANSACTION_TIMEOUT.
migration_lock_timeout: DurationPostgres lock_timeout for the migration session. Default: 5s.
"0s" disables it.
A migration that waits longer than this for a table lock fails, and
the migrator retries it (see Self::migration_lock_retries). This
stops a DDL statement that queues behind a long transaction from
blocking all traffic on that table (#3057).
Override via AUTUMN_DATABASE__MIGRATION_LOCK_TIMEOUT.
migration_lock_retries: u32Retries after a migration fails on migration_lock_timeout.
Default: 5. 0 disables the retry. Each retry waits a jittered,
exponential delay.
Override via AUTUMN_DATABASE__MIGRATION_LOCK_RETRIES.
slow_query_threshold: DurationSlow query threshold. Default: 500ms.
shards: Vec<ShardConfig>Horizontal shards, declared as [[database.shards]] entries.
Empty (the default) means the application is unsharded and only the
url/primary_url/replica_url roles above apply. When non-empty,
those top-level roles become the control topology — framework
state (jobs, scheduler locks, sessions, feature flags) lives there
while tenant data is routed across the shards. See ShardConfig.
directory_shard_router: boolRoute tenants through the control-plane _autumn_shard_directory table
(a DirectoryShardRouter)
instead of pure slot-hash routing. Default: false.
Tenants with a directory row are pinned to the named shard; everyone
else falls back to the hash router. Usually set via
AppBuilder::with_directory_shard_router.
Ignored when no shards are configured or an explicit
with_shard_router is set.
max_connections_warn_threshold: usizeEmit a startup warning when the aggregate maximum connection count
across the control topology and every shard pool reaches this value.
Default: 100.
Pool sizes multiply across shards: an N-shard fleet with a pool size
of 20 opens up to 20 * N connections, which can exhaust Postgres’s
max_connections (default 100) long before the app looks busy. This
threshold surfaces that footgun at boot. Set to 0 to disable.
fleet: Option<DatabaseFleetConfig>A fleet of SQLite databases: one file per tenant or one per routing
slot (ADR 0019). None (the default) means no fleet.
With a fleet, the top-level url is the control database (sessions,
jobs, flags) and tenant data is routed by ShardedDb,
Shards and #[repository(sharded)] to a
database file opened on first use. Requires the sqlite feature and a
sqlite: control database; mutually exclusive with
shards. See DatabaseFleetConfig.
Implementations§
Source§impl DatabaseConfig
impl DatabaseConfig
Sourcepub fn effective_primary_url(&self) -> Option<&str>
pub fn effective_primary_url(&self) -> Option<&str>
Resolved primary/write database URL.
Sourcepub fn effective_primary_postgres_url(&self) -> Option<&str>
pub fn effective_primary_postgres_url(&self) -> Option<&str>
Resolved primary/write database URL, but only when it names Postgres.
Autumn ships subsystems that are Postgres-only by construction — the
PgFlagStore, PgExperimentStore and PgConfigStore open a
diesel::PgConnection and issue pg_notify / pg_advisory_xact_lock /
jsonb SQL. Handing one a SQLite target builds a store that fails on
first use with a connection error naming a driver the operator never
chose. This accessor is what those constructors screen on, so an
unsupported target yields “no store” at construction instead.
Fails closed: a target DatabaseBackend::detect cannot classify is
refused too, rather than handed to a Postgres driver on the chance that
it might work.
Sourcepub fn effective_primary_pool_size(&self) -> usize
pub fn effective_primary_pool_size(&self) -> usize
Resolved primary/write role pool size.
Sourcepub fn effective_replica_pool_size(&self) -> usize
pub fn effective_replica_pool_size(&self) -> usize
Resolved read/replica role pool size.
Sourcepub const fn has_shards(&self) -> bool
pub const fn has_shards(&self) -> bool
Whether any [[database.shards]] entries are configured.
Sourcepub fn resolved_slot_map(&self) -> Result<Vec<usize>, ConfigError>
pub fn resolved_slot_map(&self) -> Result<Vec<usize>, ConfigError>
Resolve the slot→shard map: element s is the index (into
shards) of the shard that owns slot s.
This is the single source of truth for slot assignment, used by both
configuration validation and runtime
ShardSet construction:
- When no shard declares
slots, the slot space is auto-split into contiguous even ranges by declaration order. - When every shard declares
slots, the explicit assignments are used and must cover0..SLOT_COUNTexactly once. - Mixing declared and undeclared
slotsis an error.
§Errors
Returns ConfigError::Validation for mixed declarations,
malformed/out-of-range/duplicate slots, or incomplete coverage.
Sourcepub fn shards_auto_split(&self) -> bool
pub fn shards_auto_split(&self) -> bool
Whether all shards are using auto-split (no shard declares slots).
Returns false when no shards are configured or any shard has an
explicit slots declaration. Mixed declarations already error in
resolved_slot_map, so this is a simple
all-or-none check.
Sourcepub fn resolved_shard_assignments(
&self,
) -> Result<Vec<ShardSlotAssignment>, ConfigError>
pub fn resolved_shard_assignments( &self, ) -> Result<Vec<ShardSlotAssignment>, ConfigError>
Resolve the per-shard slot assignment as compact range strings.
Inverts resolved_slot_map (slot→shard-index)
into per-shard slot lists rendered via the same compact range notation
used in slot-map error messages. Agrees with runtime routing by
construction: the output derives from the same slot map that builds the
live ShardSet.
§Errors
Propagates any ConfigError from resolved_slot_map.
Trait Implementations§
Source§impl Clone for DatabaseConfig
impl Clone for DatabaseConfig
Source§impl Debug for DatabaseConfig
impl Debug for DatabaseConfig
Source§impl Default for DatabaseConfig
impl Default for DatabaseConfig
Source§impl<'de> Deserialize<'de> for DatabaseConfig
impl<'de> Deserialize<'de> for DatabaseConfig
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for DatabaseConfig
impl RefUnwindSafe for DatabaseConfig
impl Send for DatabaseConfig
impl Sync for DatabaseConfig
impl Unpin for DatabaseConfig
impl UnsafeUnpin for DatabaseConfig
impl UnwindSafe for DatabaseConfig
Blanket Implementations§
Source§impl<T> AggregateExpressionMethods for T
impl<T> AggregateExpressionMethods for T
Source§fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
DISTINCT modifier for aggregate functions Read moreSource§fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
ALL modifier for aggregate functions Read moreSource§fn aggregate_filter<P>(self, f: P) -> Self::Output
fn aggregate_filter<P>(self, f: P) -> Self::Output
Source§fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> AutumnCounterCaches for Twhere
T: 'static,
impl<T> AutumnCounterCaches for Twhere
T: 'static,
Source§const HAS_COUNTER_CACHES: bool = false
const HAS_COUNTER_CACHES: bool = false
Source§fn counter_caches() -> &'static [CounterCacheSpec<Self>]
fn counter_caches() -> &'static [CounterCacheSpec<Self>]
Source§impl<T> AutumnDependents for Twhere
T: ?Sized,
impl<T> AutumnDependents for Twhere
T: ?Sized,
Source§fn dependents() -> &'static [RuntimeDependentSpec]
fn dependents() -> &'static [RuntimeDependentSpec]
#[model] overrides via an inherent shadow when dependents exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoSql for T
impl<T> IntoSql for T
Source§fn into_sql<T>(self) -> Self::Expression
fn into_sql<T>(self) -> Self::Expression
self to an expression for Diesel’s query builder. Read moreSource§fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
&self to an expression for Diesel’s query builder. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> RepositoryHooksClone for Twhere
T: Clone,
impl<T> RepositoryHooksClone for Twhere
T: Clone,
Source§fn autumn_clone(&self) -> T
fn autumn_clone(&self) -> T
Source§impl<T> RepositoryHooksDefault for Twhere
T: Default,
impl<T> RepositoryHooksDefault for Twhere
T: Default,
Source§fn autumn_default() -> T
fn autumn_default() -> T
Source§impl<T, Conn> RunQueryDsl<Conn> for T
impl<T, Conn> RunQueryDsl<Conn> for T
Source§fn execute<'conn, 'query>(
self,
conn: &'conn mut Conn,
) -> <Conn as AsyncConnectionCore>::ExecuteFuture<'conn, 'query>
fn execute<'conn, 'query>( self, conn: &'conn mut Conn, ) -> <Conn as AsyncConnectionCore>::ExecuteFuture<'conn, 'query>
Source§fn load<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
fn load<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
Source§fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnectionCore,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnectionCore,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
Stream] with the returned rows. Read moreSource§fn get_result<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, LoadNext<Pin<Box<Self::Stream<'conn>>>>>
fn get_result<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, LoadNext<Pin<Box<Self::Stream<'conn>>>>>
Source§fn get_results<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
fn get_results<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
Vec with the affected rows. Read moreSource§impl<T> Scoped for T
impl<T> Scoped for T
Source§fn scope(ctx: &PolicyContext) -> ScopeQuery<'_, Self>
fn scope(ctx: &PolicyContext) -> ScopeQuery<'_, Self>
ScopeQuery for this type. Resolves the
registered scope at .load() time, not here.