Skip to main content

LifecycleManager

Struct LifecycleManager 

Source
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:

§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>

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more