pub struct LifecycleManager<R: ContainerRuntime + 'static> { /* private fields */ }Expand description
Coordinates the startup, supervision, and shutdown of every resource
declared in a LifecyclePlan.
Construct with LifecycleManager::new, optionally inject extra
environment variables with LifecycleManager::with_env, then call one of:
LifecycleManager::start_all: start all resources and return.LifecycleManager::run_until_signal: start all resources, block untilSIGINTorSIGTERM, then stop cleanly (the typicallightshuttle upentry point).
§Example
use std::time::Duration;
use lightshuttle_manifest::Manifest;
use lightshuttle_runtime::{LifecyclePlan, LifecycleManager};
use lightshuttle_runtime::testkit::MockRuntime;
let manifest = Manifest::parse(
"project:\n name: app\nresources:\n db:\n postgres:\n version: \"16\"\n"
)?;
let plan = LifecyclePlan::from_manifest(&manifest)?;
let (manager, mut events) = LifecycleManager::new(plan, MockRuntime::new());
manager.start_all().await?;
manager.stop_all(Duration::from_secs(5)).await?;Implementations§
Source§impl<R: ContainerRuntime + 'static> LifecycleManager<R>
impl<R: ContainerRuntime + 'static> LifecycleManager<R>
Sourcepub fn new(plan: LifecyclePlan, runtime: R) -> (Self, Receiver<LifecycleEvent>)
pub fn new(plan: LifecyclePlan, runtime: R) -> (Self, Receiver<LifecycleEvent>)
Build a manager bound to plan and runtime. Returns a fresh
event subscriber alongside; further subscribers can be obtained
from Self::subscribe_events.
Sourcepub fn with_env(self, env: HashMap<String, String>) -> Self
pub fn with_env(self, env: HashMap<String, String>) -> Self
Merge additional environment variables into the interpolation context used for every resource.
Variables provided here take precedence over same-named variables from
the ambient process environment. The typical use-case is forwarding the
contents of a .env file so that ${env.NAME} references in the
manifest resolve to the file values. Call before Self::start_all.
Returns self for method chaining.
Sourcepub fn check_required_env(&self) -> Result<(), LifecycleError>
pub fn check_required_env(&self) -> Result<(), LifecycleError>
Scan every resource spec for ${env.VAR} references that cannot be
resolved and return a single error listing all missing names.
Delegates to LifecyclePlan::env_report so the fail-fast preflight
and the lightshuttle secrets check diagnostic command share one source
of truth. Call before Self::start_all to surface missing variables
before any container is started, which avoids a partial stack start
followed by an immediate rollback.
§Errors
Returns crate::LifecycleError::MissingEnvVars with a sorted,
deduplicated list of every missing variable name.
Sourcepub async fn start_all(&self) -> Result<(), LifecycleError>
pub async fn start_all(&self) -> Result<(), LifecycleError>
Start every resource in topological order, with independent branches starting in parallel.
Each resource waits for its dependencies to become ready (i.e. reach
crate::NodeStatus::Running or crate::NodeStatus::Healthy) before
calling crate::ContainerRuntime::start. Readiness is gate-kept by the
healthcheck: a container with a declared healthcheck must report
crate::ContainerStatus::Healthy before its dependents may proceed.
On the first failure, every resource that has already started is stopped automatically (best-effort, 10-second grace) before the error is returned.
§Errors
Returns the first crate::LifecycleError encountered. Secondary
failures from the automatic rollback are logged but not returned.
Sourcepub async fn stop_all(&self, grace: Duration) -> Result<(), LifecycleError>
pub async fn stop_all(&self, grace: Duration) -> Result<(), LifecycleError>
Stop every resource in reverse topological order.
Each resource receives SIGTERM. After grace elapses, the runtime
sends SIGKILL to any container that has not exited yet. Resources are
stopped in the reverse of startup order (dependents before their
dependencies). After all containers are removed, the per-project bridge
network is torn down (failure is logged but does not abort the call).
§Errors
Returns the first crate::LifecycleError::Stop encountered. Other
stop failures are logged but not propagated.
Sourcepub async fn run_until_signal(
&self,
grace: Duration,
) -> Result<(), LifecycleError>
pub async fn run_until_signal( &self, grace: Duration, ) -> Result<(), LifecycleError>
Start the stack, wait for SIGINT or SIGTERM, then stop cleanly.
This is the opinionated entry point for the lightshuttle up command.
It calls Self::start_all, blocks until a shutdown signal is received,
then calls Self::stop_all with the provided grace window.
On Unix, both SIGINT (Ctrl+C) and SIGTERM trigger the teardown.
On Windows, only Ctrl+C is intercepted.
§Example
use std::time::Duration;
use lightshuttle_manifest::Manifest;
use lightshuttle_runtime::{DockerRuntime, LifecyclePlan, LifecycleManager};
let manifest = Manifest::parse(
"project:\n name: app\nresources:\n db:\n postgres:\n version: \"16\"\n"
)?;
let plan = LifecyclePlan::from_manifest(&manifest)?;
let runtime = DockerRuntime::connect()?;
let (manager, _events) = LifecycleManager::new(plan, runtime);
// Blocks until Ctrl+C or SIGTERM.
manager.run_until_signal(Duration::from_secs(30)).await?;§Errors
Propagates errors from Self::start_all or Self::stop_all.
Sourcepub async fn restart_one(&self, resource: &str) -> Result<(), LifecycleError>
pub async fn restart_one(&self, resource: &str) -> Result<(), LifecycleError>
Restart a single resource without touching its dependents.
The target is stopped via SIGTERM (10-second grace window), its
container id and started-at timestamp are cleared, then the full
start_one cycle is re-run from the same cached spec. Three events are
emitted on the lifecycle channel in order: crate::LifecycleEvent::ResourceStopped,
crate::LifecycleEvent::ResourceStarted, crate::LifecycleEvent::ResourceHealthy.
Dependents keep running. Their internal watch channels observe the
target’s status transition through Stopped -> Pending -> Starting
-> Running -> Healthy, so upstream processes that hold a watch
receiver can pause themselves locally until the dependency is healthy
again.
§Errors
Returns crate::LifecycleError::ResourceNotFound when resource is
not part of the plan, or a crate::LifecycleError::Start /
crate::LifecycleError::Stop variant on runtime failure.
Sourcepub fn subscribe_events(&self) -> Receiver<LifecycleEvent>
pub fn subscribe_events(&self) -> Receiver<LifecycleEvent>
Open a new subscription on the lifecycle event broadcast.
Multiple subscribers can read concurrently. Subscribers that
fall more than 256 events behind (the broadcast channel capacity)
observe a RecvError::Lagged and have to resynchronise.
Auto Trait Implementations§
impl<R> Freeze for LifecycleManager<R>
impl<R> RefUnwindSafe for LifecycleManager<R>where
R: RefUnwindSafe,
impl<R> Send for LifecycleManager<R>
impl<R> Sync for LifecycleManager<R>
impl<R> Unpin for LifecycleManager<R>
impl<R> UnsafeUnpin for LifecycleManager<R>
impl<R> UnwindSafe for LifecycleManager<R>where
R: RefUnwindSafe,
Blanket Implementations§
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
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> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request