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 clientasync- Async client support with tokioserver- Supervisor daemon with full feature setpid1- PID 1 init process (Linux only)full- Everything: client + server + pid1 + tui
§Quick Start
§Blocking Client
use zinit::ZinitHandle;
// Connect to supervisor
let z = ZinitHandle::new().expect("Failed to connect");
// List all services
let services = z.list().expect("Failed to list");
println!("Services: {:?}", services);
// Get service status
let status = z.status("my-service").expect("Service not found");
println!("Status: {:?}", status.state);§Async Client
use zinit::ZinitClient;
// For async operations, use ZinitClient
// Note: Full async example requires tokio runtime§Creating Services
use zinit::{ZinitHandle, client::client::ServiceConfigBuilder};
let z = ZinitHandle::new().expect("Failed to connect");
// Create a service config using the builder
let config = ServiceConfigBuilder::new("my-app")
.exec("/usr/bin/my-app --daemon")
.dir("/opt/my-app")
.env("APP_ENV", "production")
.port(8080) // Declare TCP port if used
.build();
// Add the service
match z.service_set(config) {
Ok(result) => println!("Created service: {}", result.name),
Err(e) => eprintln!("Failed to create service: {}", e),
}§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, check the Error type in relevant modules.
§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 client::ZinitClient;pub use client::ZinitHandle;pub use sdk::DependencyDef;pub use sdk::LifecycleDef;pub use sdk::LoggingDef;pub use sdk::RestartPolicy;pub use sdk::ServiceClass;pub use sdk::ServiceConfig;pub use sdk::ServiceDef;pub use sdk::ServiceStatus;pub use sdk::SocketAddr;pub use sdk::State;pub use sdk::Status;pub use sdk::WhyBlocked;pub use sdk::XinetConfig;pub use sdk::XinetStatus;