pub struct BosonBuilder { /* private fields */ }Expand description
Builder for Boson.
Required: a queue backend (queue_backend or
queue_backend_from_global) and an
execution_context_factory. For #[task] handlers on a
worker process, call auto_registry so inventory entries from linked
crates are collected.
Topology (see the boson crate Getting started):
| Mode | Builder posture |
|---|---|
| Mode 1 — Embedded | auto_registry + build (or build_manual in tests) |
| Mode 2 — Enqueue host | auto_registry + without_worker + build + configure |
| Mode 2 — Worker | worker_id + lease_ttl_secs (> 0) + auto_registry + build |
Optional: ops_log / ops_log_console for
telemetry (OpsLog).
§Examples
§Mode 1 — embedded (enqueue + worker in one process)
After build, call configure if callers use macro
send_with (not required when holding Boson and calling Boson::enqueue directly).
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::JsonExecutionContextFactory;
use boson_runtime::{configure, Boson};
let boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.build()?;
configure(boson);§Mode 2 — enqueue-only host
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::JsonExecutionContextFactory;
use boson_runtime::{configure, Boson};
// Production Mode 2: use Sqlite/Postgres/Redis/NATS — mem cannot cross processes.
let boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.without_worker()
.build()?;
configure(boson);Implementations§
Source§impl BosonBuilder
impl BosonBuilder
Sourcepub fn build(self) -> Result<Boson>
pub fn build(self) -> Result<Boson>
Build Boson and optionally spawn the background worker loop.
When without_worker was not set (default), a Tokio task polls
queued jobs, claims them, dispatches registered handlers (from
auto_registry or registry), and applies retry
policy — Mode 1 embedded or Mode 2 worker.
When without_worker was set, no claim loop starts; use this
for Mode 2 enqueue hosts, then configure + send_with.
Enqueue with Boson::enqueue or macro send_with after configure.
For step-driven tests, use build_manual instead.
Getting started: Mode 1 / Mode 2.
§Example — Mode 1 embedded
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::JsonExecutionContextFactory;
use boson_runtime::{configure, Boson};
let boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.build()?; // worker loop runs in the background
configure(boson);§Errors
Returns BosonError::InvalidConfig if no execution context factory was set, or an error
if the queue backend cannot be resolved.
Sourcepub fn build_manual(self) -> Result<(Boson, ManualWorker)>
pub fn build_manual(self) -> Result<(Boson, ManualWorker)>
Build without a background worker; returns ManualWorker for step-driven execution.
Prefer this in tests when you want to enqueue then call
ManualWorker::try_run_next. For Mode 2 enqueue-only
production hosts that never drain locally, prefer without_worker
buildinstead (noManualWorkerhandle needed).
§Example — enqueue then drain one job
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::{ExecutionContext, JsonExecutionContextFactory};
use boson_macros::task;
use boson_runtime::{configure, Boson, ManualWorker};
#[task(name = "ping")]
async fn ping(_ctx: Box<dyn ExecutionContext>, n: u32) -> boson_core::Result<()> {
let _ = n;
Ok(())
}
let (boson, manual): (_, ManualWorker) = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.without_worker()
.build_manual()?;
configure(boson);
Ping::send_with(serde_json::json!({}), PingParams { n: 1 }).await?;
assert!(manual.try_run_next().await);§Errors
Returns BosonError::InvalidConfig if no execution context factory was set, or an error
if the queue backend cannot be resolved.
Source§impl BosonBuilder
impl BosonBuilder
Sourcepub fn worker_id(self, worker_id: impl Into<String>) -> Self
pub fn worker_id(self, worker_id: impl Into<String>) -> Self
Worker identity for lease claims (default: INSTANCE_ID / BOSON_WORKER_ID / boson-worker-1).
Required to be unique per process in Mode 2 (multiple workers sharing a backend). See
WorkerSettings and the
Mode 2
section on the boson crate.
§Example
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::JsonExecutionContextFactory;
use boson_runtime::Boson;
let _boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.worker_id("worker-a")
.lease_ttl_secs(30)
.auto_registry()
.build()?;Sourcepub const fn lease_ttl_secs(self, secs: i64) -> Self
pub const fn lease_ttl_secs(self, secs: i64) -> Self
Run lease TTL in seconds; when > 0, claim path acquires leases before job claim.
Use 0 (default) for Mode 1 embedded monoliths. Use a positive value for Mode 2 so
workers do not double-execute the same run. Env override: BOSON_LEASE_TTL_SECS.
See WorkerSettings.
Sourcepub fn runtime_label(self, label: impl Into<String>) -> Self
pub fn runtime_label(self, label: impl Into<String>) -> Self
Telemetry/runtime label (default embedded; bench uses topology slug).
Sourcepub fn worker_pools(
self,
pools: impl IntoIterator<Item = impl Into<String>>,
) -> Self
pub fn worker_pools( self, pools: impl IntoIterator<Item = impl Into<String>>, ) -> Self
Restrict this worker to specific pools (comma-free list). Unset = poll all queued pools.
Also available via BOSON_WORKER_POOLS=pool-a,pool-b. Pin workers to disjoint pool sets
for shared-nothing scaling (each worker skips distinct_pools_queued fan-out).
Sourcepub const fn worker_poll_interval_ms(self, ms: u64) -> Self
pub const fn worker_poll_interval_ms(self, ms: u64) -> Self
Milliseconds between worker poll ticks (default 50; use 0 for bench drain tests).
Sourcepub const fn idempotency_mode(self, mode: IdempotencyMode) -> Self
pub const fn idempotency_mode(self, mode: IdempotencyMode) -> Self
Default enqueue idempotency mode when a task does not override it.
boson_core::IdempotencyMode::Lwt (default) is exactly-once under concurrent enqueue.
boson_core::IdempotencyMode::None is at-least-once and skips coordination (higher throughput).
Sourcepub fn queue_backend(self, backend: Arc<dyn QueueBackend>) -> Self
pub fn queue_backend(self, backend: Arc<dyn QueueBackend>) -> Self
Inject queue persistence backend explicitly.
Pick the backend for your topology: MemQueueBackend
for Mode 1 only; SQLite/Postgres/Redis/NATS when processes share a queue. See the
boson crate backend table.
Sourcepub fn queue_backend_from_global(self) -> Self
pub fn queue_backend_from_global(self) -> Self
Use global QueueRouter default backend.
Sourcepub fn execution_context_factory(
self,
factory: impl ExecutionContextFactory + 'static,
) -> Self
pub fn execution_context_factory( self, factory: impl ExecutionContextFactory + 'static, ) -> Self
Identity factory for handler dispatch.
Maps stored actor_json to Box<dyn ExecutionContext> when a worker runs a job. For examples
and smoke tests, pass JsonExecutionContextFactory;
production apps typically implement ExecutionContextFactory.
§Example
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::JsonExecutionContextFactory;
use boson_runtime::Boson;
let _boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.build()?;Sourcepub fn execution_context_factory_arc(
self,
factory: Arc<dyn ExecutionContextFactory>,
) -> Self
pub fn execution_context_factory_arc( self, factory: Arc<dyn ExecutionContextFactory>, ) -> Self
Identity factory from existing Arc.
Sourcepub fn ops_log(self, log: impl OpsLog + 'static) -> Self
pub fn ops_log(self, log: impl OpsLog + 'static) -> Self
Install ops log adapter (default boson_telemetry::NoOpsLog).
Prefer this or ops_log_console over installing an OpsLog
ad hoc. See boson_telemetry::OpsLog for adapter choices.
Sourcepub fn ops_log_console(self) -> Self
pub fn ops_log_console(self) -> Self
Use console stderr ops log (ConsoleOpsLog).
Sourcepub fn registry(self, registry: Arc<TaskRegistry>) -> Self
pub fn registry(self, registry: Arc<TaskRegistry>) -> Self
Use an existing task registry (e.g. testkit manual registration).
Sourcepub const fn auto_registry(self) -> Self
pub const fn auto_registry(self) -> Self
Discover tasks registered via Quark inventory (for example #[boson::task]).
Worker processes need this (or registry) so handlers are available
to the claim loop. Enqueue hosts also need it (or a manual registry) because
send_with / Boson::enqueue resolve task descriptors for priority, pool, and policies
— they do not run handlers.
The binary must link every crate that defines inventory submissions; otherwise tasks
defined in library crates will not appear in the registry. Add the task-owning crate as a
dependency (for example use my_worker as _;).
Getting started: Mode 1 / Mode 2.
§Example
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::{ExecutionContext, JsonExecutionContextFactory};
use boson_macros::task;
use boson_runtime::{configure, Boson};
#[task(name = "ping")]
async fn ping(_ctx: Box<dyn ExecutionContext>) -> boson_core::Result<()> {
Ok(())
}
// When handlers live in a library crate, link it from `main`:
// use my_worker as _;
let boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.build()?;
configure(boson);Sourcepub const fn without_worker(self) -> Self
pub const fn without_worker(self) -> Self
Do not spawn the background worker loop.
Use for:
- Mode 2 enqueue hosts — this process only
configures and callssend_with; a separate worker binary drains the shared backend - Tests — pair with
build_manualandManualWorker
Getting started: Mode 2 — enqueue binary.
§Example — enqueue-only process
use std::sync::Arc;
use boson_backend_mem::MemQueueBackend;
use boson_core::JsonExecutionContextFactory;
use boson_runtime::{configure, Boson};
let boson = Boson::builder()
.queue_backend(Arc::new(MemQueueBackend::new()))
.execution_context_factory(JsonExecutionContextFactory)
.auto_registry()
.without_worker()
.build()?;
configure(boson);