zinit 0.3.9

Process supervisor with dependency management
Documentation
//! Advanced Zinit Client Usage Examples
//!
//! This example demonstrates advanced features like creating services with
//! dependencies, health checks, and complex configurations using the builder pattern.
//!
//! To run this example:
//! ```bash
//! cargo run --example zinit_advanced --manifest-path packages/clients/Cargo.toml
//! ```

use anyhow::Result;
use herolib_clients::zinit::{ServiceConfigBuilder, ZinitHandle};

fn main() -> Result<()> {
    println!("=== Advanced Zinit Service Management ===\n");

    // Connect to zinit server
    println!("1. Connecting to zinit server...");
    let z = match ZinitHandle::new() {
        Ok(handle) => handle,
        Err(e) => {
            eprintln!("✗ Failed to connect to zinit server: {}", e);
            eprintln!("\nPlease start the zinit server with: zinit");
            return Ok(());
        }
    };
    println!("✓ Connected to zinit server\n");

    // Create a database service with health check
    println!("2. Creating database service:");
    let db_config = ServiceConfigBuilder::new("database")
        .exec("postgres -D /var/lib/postgres")
        .dir("/var/lib/postgres")
        .critical(true)
        .restart("on-failure")
        .restart_delay_ms(5000)
        .max_restarts(5)
        .health_tcp("127.0.0.1:5432")
        .health_interval_ms(10000)
        .log_buffer_lines(5000)
        .log_file("/var/log/postgres.log")
        .build();

    match z.service_set(db_config) {
        Ok(_) => println!(),
        Err(e) => println!("✗ Error: {}\n", e),
    }

    // Create an app service that depends on database
    println!("3. Creating app service with database dependency:");
    let app_config = ServiceConfigBuilder::new("api_server")
        .exec("node /app/server.js")
        .dir("/app")
        .env("DB_HOST", "localhost")
        .env("DB_PORT", "5432")
        .env("NODE_ENV", "production")
        .requires("database")
        .after("database")
        .restart("on-failure")
        .restart_delay_ms(5000)
        .max_restarts(5)
        .health_http("http://localhost:3000/health")
        .log_buffer_lines(10000)
        .build();

    match z.service_set(app_config) {
        Ok(_) => println!(),
        Err(e) => println!("✗ Error: {}\n", e),
    }

    // Create an alternative API service with conflicts
    println!("4. Creating alternative API service (conflicts with api_server):");
    let alt_config = ServiceConfigBuilder::new("api_server_v2")
        .exec("python3 /app/main.py")
        .dir("/app")
        .env("DB_HOST", "localhost")
        .conflicts("api_server")
        .build();

    match z.service_set(alt_config) {
        Ok(_) => println!(),
        Err(e) => println!("✗ Error: {}\n", e),
    }

    // List all services
    println!("5. All services:");
    match z.list() {
        Ok(services) => {
            println!("   Total services: {}", services.len());
            for service in &services {
                match z.status(service) {
                    Ok(status) => {
                        println!(
                            "   - {} (state: {:?}, pid: {:?})",
                            service, status.state, status.pid
                        );
                    }
                    Err(_) => {
                        println!("   - {} (status unavailable)", service);
                    }
                }
            }
            println!();
        }
        Err(e) => {
            println!("   Error listing services: {}\n", e);
        }
    }

    // Service dependency tree
    println!("6. Service dependency tree:");
    match z.tree() {
        Ok(tree_output) => {
            println!("{}", tree_output);
            println!();
        }
        Err(e) => {
            println!("   Error getting tree: {}\n", e);
        }
    }

    // Get detailed information about a specific service
    println!("7. Service configuration details:");
    match z.list() {
        Ok(services) => {
            if let Some(service_name) = services.first() {
                println!("   Checking service: {}", service_name);

                match z.service_get(service_name) {
                    Ok(config) => {
                        println!("   Name: {}", config.service.name);
                        println!("   Exec: {}", config.service.exec);
                        println!("   Oneshot: {}", config.service.oneshot);
                        println!("   Critical: {}", config.service.critical);

                        if !config.service.env.is_empty() {
                            println!("   Environment variables:");
                            for (key, value) in &config.service.env {
                                println!("     {} = {}", key, value);
                            }
                        }

                        if !config.dependencies.requires.is_empty() {
                            println!("   Requires: {:?}", config.dependencies.requires);
                        }

                        if !config.dependencies.after.is_empty() {
                            println!("   After: {:?}", config.dependencies.after);
                        }

                        // Try to get logs
                        match z.logs_tail(Some(service_name), Some(5)) {
                            Ok(logs) => {
                                println!("   Recent logs ({} entries):", logs.len());
                                for (i, log) in logs.iter().take(3).enumerate() {
                                    println!("     [{}] {}", i, log.content);
                                }
                            }
                            Err(_) => {
                                println!("   (No logs available)");
                            }
                        }
                        println!();
                    }
                    Err(e) => {
                        println!("   Error getting config: {}\n", e);
                    }
                }
            } else {
                println!("   No services available\n");
            }
        }
        Err(e) => {
            println!("   Error: {}\n", e);
        }
    }

    // Service control operations
    println!("8. Service control operations:");
    match z.list() {
        Ok(services) => {
            if let Some(service_name) = services.first() {
                println!("   Operating on service: {}", service_name);

                // Restart
                match z.restart(service_name) {
                    Ok(_) => println!(),
                    Err(e) => println!("   ✗ Restart failed: {}\n", e),
                }

                // Get updated status
                match z.status(service_name) {
                    Ok(status) => {
                        println!("   Current state: {:?}\n", status.state);
                    }
                    Err(e) => {
                        println!("   ✗ Status check failed: {}\n", e);
                    }
                }
            }
        }
        Err(e) => {
            println!("   Error: {}\n", e);
        }
    }

    // System operations
    println!("9. System operations:");

    // Try to list xinit proxies
    match z.xinet_list() {
        Ok(proxies) => {
            println!("   Xinit proxies: {}", proxies.len());
            for proxy in &proxies {
                println!("     - {}", proxy);
            }
            println!();
        }
        Err(e) => {
            println!("   No xinit proxies or error: {}\n", e);
        }
    }

    // Clean up - delete created services
    println!("10. Cleaning up services:");
    for service in &["database", "api_server", "api_server_v2"] {
        match z.service_delete(service) {
            Ok(_) => println!("✓ Deleted {}", service),
            Err(e) => println!("✗ Error deleting {}: {}", service, e),
        }
    }

    println!("\n✓ Done");
    Ok(())
}