Expand description
§zinit - Process Supervisor with Dependency Management
Zinit is a lightweight process supervisor with sophisticated dependency management. It’s designed to be simpler than systemd while providing the core features needed for service management in containers, VMs, and bare-metal systems.
§Overview
Zinit manages services through:
- State Machine: 7-state service lifecycle (Inactive, Blocked, Starting, Running, Stopping, Exited, Failed)
- Dependency Graph: Supports
after,requires,wants, andconflictsdependencies - Service Classes:
user(bulk-controllable) andsystem(protected) services - JSON-RPC 2.0 API: Unix socket IPC with 44 RPC methods
- Health Checks: TCP, HTTP, and exec-based health monitoring
- Process Groups: Proper signal handling for shell-wrapped processes
- Hot Restart: State persistence and process adoption on restart
§Architecture
The crate is organized into modules:
sdk- Shared types, configuration, RPC protocol, and client librariesserver- (withserverfeature) Main supervisor daemonclient- (withclientfeature) CLI interface
§Features
sdk- Shared types and protocol (always included in lib)client- CLI client interfacetui- Terminal UI for interactive clientrepl- Interactive REPL shellasync- Async client support with tokioserver- Supervisor daemon with full feature setpid1- PID 1 init process (Linux only)full- Everything: client + server + pid1 + tui + repl
§Quick Start
§Blocking Client
use zinit::{ZinitClient, ServiceConfig, ServiceDef};
// Connect to supervisor
let mut client = ZinitClient::connect_default().expect("Failed to connect");
// List all services
let services = client.list().expect("Failed to list");
println!("Services: {:?}", services);
// Get service status
let status = client.status("my-service").expect("Service not found");
println!("Status: {:?}", status.state);§Async Client
use zinit::AsyncZinitClient;
let client = AsyncZinitClient::new(
&std::path::PathBuf::from("/var/run/zinit.sock")
).expect("Failed to create client");
let status = client.status("my-service").await.expect("Status failed");
println!("PID: {}", status.pid);§Creating Services
use zinit::{ZinitClient, ServiceConfig, ServiceDef, ServiceClass, RestartPolicy};
use std::collections::HashMap;
let mut client = ZinitClient::connect_default().expect("Failed to connect");
// Create a service config
let mut config = ServiceConfig {
service: ServiceDef {
name: "my-app".to_string(),
exec: "/usr/bin/my-app --daemon".to_string(),
dir: Some("/opt/my-app".to_string()),
env: HashMap::new(),
status: "start".to_string(),
class: ServiceClass::User,
critical: false,
oneshot: false,
},
..Default::default()
};
// Add the service
let result = client.add(&config, true).expect("Add failed");
println!("Created service: {}", result.name);§Managing Dependencies
# In /etc/zinit/services/app.toml
[service]
name = "app"
exec = "/usr/bin/app"
[dependencies]
requires = ["database"]
after = ["logger"]
wants = ["cache"]
conflicts = ["dev-mode"]
[lifecycle]
restart = "on-failure"
start_timeout_ms = 30000
stop_timeout_ms = 10000§RPC Methods
The supervisor exposes 44 RPC methods over JSON-RPC 2.0:
§System
system.ping- Check if supervisor is alivesystem.shutdown- Gracefully shutdownsystem.reboot- Reboot system (PID 1 only)system.prepare_restart- Save state for hot restart
§Services
service.list- List service namesservice.list_full- List services with stateservice.status- Get service statusservice.stats- Get resource usage (PID, memory, CPU)service.start/service.stop/service.restartservice.create/service.delete- Manage servicesservice.tree- Show dependency treeservice.why- Explain why service is blockedservice.start_all/service.stop_all- Bulk operations (user-class only)
§Logging
logs.get- Get log lineslogs.tail- Get structured logslogs.filter- Filter logs by service/stream/time
§Xinet (Socket Activation)
xinet.create/xinet.delete- Manage proxiesxinet.list/xinet.status- Query proxies
See sdk::protocol for complete RPC types and docs/OPENRPC_IMPLEMENTATION.md for detailed API documentation.
§Configuration Format
Services are configured in TOML format:
[service]
name = "my-service"
exec = "/usr/bin/my-service --daemon"
dir = "/opt/my-service"
class = "user" # or "system"
critical = false # Fail boot if critical (PID 1 only)
oneshot = false # Exit without restart
[dependencies]
after = ["database"]
requires = ["logger"]
wants = ["cache"]
conflicts = ["competitor"]
[lifecycle]
restart = "on-failure" # always, on-failure, never
restart_delay_ms = 1000
start_timeout_ms = 30000
stop_timeout_ms = 10000
stop_signal = "SIGTERM"
max_restarts = 10
[health]
type = "tcp"
target = "localhost:8080"
interval_ms = 10000
timeout_ms = 5000
retries = 3
[logging]
buffer_lines = 1000
file = "/var/log/my-service.log"§Operating Modes
§Standalone Server
zinit-server --config-dir /etc/zinit/services§Container Mode
zinit init -c --config-dir /etc/zinit/services§VM/Bare-metal (as PID 1)
zinit init --config-dir /etc/zinit/services --system-dir /etc/zinit/system§Platform Support
- Linux: Full support including PID 1 mode with systemd-style boot
- macOS/Darwin: Client and server support (no PID 1 mode)
- Windows: Client support (via WSL recommended)
Path handling is platform-aware:
- Linux:
/run/zinit.sock,/etc/zinit/services - macOS/Windows:
$HOME/hero/var/zinit.sock,$HOME/hero/cfg/zinit
See sdk::socket for path configuration details.
§Examples
See the examples/ directory for complete working examples:
list_services.rs- Enumerate servicesmonitor_service.rs- Watch service state changesdependency_graph.rs- Visualize dependenciescreate_service.rs- Dynamically create services
§Error Handling
Most operations return Result<T, Box<dyn std::error::Error>> for convenience.
For detailed error information, use the underlying error types:
sdk::protocol::RpcError- RPC protocol errors- [
sdk::validate::ValidationError] - Configuration validation errors
§Concurrency
- Clients are single-threaded (synchronous)
- Server uses tokio async runtime with
RwLock<ServiceGraph>for safe concurrent access - IPC is over Unix domain sockets with newline-delimited JSON
§See Also
Re-exports§
pub use sdk::DependencyDef;pub use sdk::FailureReason;pub use sdk::LifecycleDef;pub use sdk::LoggingDef;pub use sdk::OkResponse;pub use sdk::RestartPolicy;pub use sdk::ServiceClass;pub use sdk::ServiceConfig;pub use sdk::ServiceDef;pub use sdk::ServiceState;pub use sdk::ServiceStats;pub use sdk::ServiceStatus;pub use sdk::State;pub use sdk::Status;pub use sdk::WhyBlocked;pub use sdk::ZinitClient;pub use sdk::protocol;pub use sdk::socket;pub use sdk::validate;pub use sdk::xinet;