lightshuttle_runtime/lib.rs
1#![deny(missing_docs)]
2//! Container runtime backends and lifecycle manager for LightShuttle.
3//!
4//! # Crate placement in the stack
5//!
6//! ```text
7//! lightshuttle-spec (domain types, ContainerSpec)
8//! lightshuttle-manifest (YAML parsing, interpolation)
9//! |
10//! lightshuttle-runtime <-- this crate
11//! |
12//! lightshuttle-control (REST/HTTP control plane)
13//! lightshuttle-otel (OpenTelemetry instrumentation)
14//! ```
15//!
16//! This crate depends on `lightshuttle-spec` (for [`ContainerSpec`] and
17//! related domain types) and `lightshuttle-manifest` (for parsed manifests
18//! fed into [`LifecyclePlan::from_manifest`]). It is consumed by
19//! `lightshuttle-control` (the control plane) and `lightshuttle-otel`.
20//!
21//! # Core abstractions
22//!
23//! ## [`ContainerRuntime`] trait
24//!
25//! The narrow abstraction that hides every daemon-specific detail.
26//! The lifecycle manager calls only the methods declared by this trait.
27//! [`DockerRuntime`] is the first concrete implementation, backed by the
28//! `bollard` crate. Tests and downstream crates use [`testkit::MockRuntime`]
29//! as a drop-in replacement that requires no Docker daemon.
30//!
31//! ## [`LifecyclePlan`]
32//!
33//! Computed from a parsed manifest by [`LifecyclePlan::from_manifest`].
34//! Performs a topological sort (Kahn's algorithm) over the declared
35//! `depends_on` graph so the manager can start independent branches in
36//! parallel and block each resource until its dependencies are ready.
37//!
38//! ## [`LifecycleManager`]
39//!
40//! Orchestrates the full `up` and `down` lifecycle:
41//!
42//! 1. Starts every resource in topological order, independent branches in
43//! parallel, via `tokio::spawn`.
44//! 2. Waits for each container to pass its healthcheck (or to reach
45//! [`ContainerStatus::Running`] when no healthcheck is declared).
46//! 3. Publishes [`LifecycleEvent`] on a broadcast channel so the CLI,
47//! dashboard, and REST layer can observe progress.
48//! 4. On `SIGINT` or `SIGTERM` (see [`LifecycleManager::run_until_signal`]),
49//! stops all resources in reverse topological order, sends `SIGTERM` and
50//! then `SIGKILL` after the configured grace window, and tears down the
51//! per-project bridge network.
52//!
53//! # Quick start (no Docker daemon)
54//!
55//! ```rust,no_run
56//! use std::collections::HashMap;
57//! use std::time::Duration;
58//!
59//! use lightshuttle_manifest::Manifest;
60//! use lightshuttle_runtime::{LifecyclePlan, LifecycleManager, DockerRuntime};
61//!
62//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
63//! let yaml = r#"
64//! project:
65//! name: myapp
66//! resources:
67//! db:
68//! postgres:
69//! version: "16"
70//! "#;
71//!
72//! let manifest = Manifest::parse(yaml)?;
73//! let plan = LifecyclePlan::from_manifest(&manifest)?;
74//! let runtime = DockerRuntime::connect()?;
75//! let (manager, _events) = LifecycleManager::new(plan, runtime);
76//!
77//! // Blocks until SIGINT/SIGTERM, then tears the stack down cleanly.
78//! manager.run_until_signal(Duration::from_secs(30)).await?;
79//! # Ok(())
80//! # }
81//! ```
82//!
83//! See `docs/spec/manifest-v0.md` in the main repository for the full
84//! manifest specification.
85
86pub use crate::docker::{DockerRuntime, LABEL_PROJECT, LABEL_RESOURCE, ManagedContainer};
87pub use crate::error::{Result, RuntimeError};
88pub use crate::lifecycle::{
89 EnvReport, EnvSource, EnvVarReport, EnvVarStatus, LifecycleError, LifecycleEvent,
90 LifecycleHandle, LifecycleHandleError, LifecycleManager, LifecyclePlan, ManagerHandle,
91 NodeStatus, PlanNode, ResourceStatus, ResourceView,
92};
93pub use crate::runtime::{
94 ContainerId, ContainerRuntime, ContainerStatus, LogChunk, LogChunkStream, LogStream,
95};
96pub use lightshuttle_spec::{
97 ContainerSpec, HealthcheckSpec, ImageSource, PortBinding, ResolvedResource, ResourceOutputs,
98 SpecError, VolumeBinding, VolumeSource, from_resource,
99};
100
101mod docker;
102mod error;
103mod lifecycle;
104mod runtime;
105
106/// In-memory [`ContainerRuntime`] and supporting helpers for tests.
107///
108/// See [`testkit::MockRuntime`] for the main type.
109pub mod testkit;