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