arcature 2026.2.1

Arcature application framework: a high-level Application facade over the certified Arcature subsystems, with the low-level Axum/Tower escape hatch preserved.
Documentation
//! [`JobsRegistry`] — how the engine obtains the job handler registry.
//!
//! A job handler registry can be constructed in two ways:
//!
//! - **Static** ([`JobsRegistry::Static`]): built before the engine starts, with
//!   no access to runtime state. The existing `.jobs(registry)` builder path.
//! - **Lifecycle** ([`JobsRegistry::WithDb`]): built *after* the engine
//!   connects the `PgPool` at startup, so handlers can capture a `Db` clone
//!   (or any handle derived from it). The `.jobs_with_db(closure)` builder
//!   path.
//!
//! The A13 job-handler contract is `Fn(J) -> Fut` — the handler receives only
//!   the typed payload, not application state. For a handler that needs the
//!   database (the common dogfood case), the app supplies a closure
//!   `Fn(&Db) -> Registry` that captures a `Db` clone into each handler; the
//!   engine invokes it inside [`startup`](super::startup) after the pool
//!   connects, then spawns the worker over the shared pool. This keeps the
//!   certified `arcature-jobs` `Fn(J)` API unchanged; only the *registry-
//!   construction* moment moves into the lifecycle.
//!
//! `jobs` implies `db` (see `Cargo.toml`), so `crate::db::Db` is always in
//! scope under this module's feature gate.

use std::sync::Arc;

/// The job handler registry, either pre-built or lifecycle-built.
#[cfg(feature = "jobs")]
pub(crate) enum JobsRegistry {
    /// A registry built before startup (no runtime state available).
    Static(crate::jobs::Registry),

    /// A closure that builds the registry from the connected `Db` at
    /// startup. The engine calls it inside `startup`, after `Db::connect`,
    /// then spawns the worker over the shared pool. Handlers may capture a
    /// `Db` clone (or a shared client built from the pool) into their
    /// closures.
    WithDb(Arc<dyn Fn(&crate::db::Db) -> crate::jobs::Registry + Send + Sync + 'static>),
}

#[cfg(feature = "jobs")]
impl JobsRegistry {
    /// Resolves this into a concrete [`crate::jobs::Registry`] for the worker.
    ///
    /// `Static` returns the stored registry as-is. `WithDb` invokes the
    /// closure with the connected `Db`. The `Db` is borrowed only for the
    /// duration of the call; handlers that need a handle must clone it
    /// (the handle is `Clone` — an `Arc`-backed pool reference).
    pub(crate) fn resolve(self, db: &crate::db::Db) -> crate::jobs::Registry {
        match self {
            Self::Static(registry) => registry,
            Self::WithDb(build) => build(db),
        }
    }
}