← Back to Blog

Building Lightning-Fast DevOps CLI Tools in Rust

How I built a reliable WhatsApp AI shopping assistant for Clickmothercare that survives hallucinated products, silent save failures, and multi-agent handoff bugs.

Anas Rhimi
Anas Rhimi August 2026 • 8 min read

Python and Bash are the traditional languages of DevOps. However, when automating infrastructure tasks that require massive concurrency—such as fetching logs from 5,000 servers, or parsing gigabytes of JSON asynchronously—interpreted languages often bottleneck on the Global Interpreter Lock (GIL) or process-spawning overhead. Rust has emerged as a powerhouse for DevOps tooling, producing single, dependency-free binaries with blazing-fast async runtimes.

The Challenge: Concurrent API Polling

Imagine a CLI tool that needs to query a health endpoint across hundreds of microservices. A Bash script using a for loop and curl will take minutes. We can solve this in seconds using Rust with the tokio async runtime and reqwest.

The Rust Async Implementation

Here is the core logic for a robust, concurrent health-checker CLI.

use reqwest::Client;
use std::time::Duration;
use tokio::task::JoinSet;

// Custom Error type for robust error handling
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

#[tokio::main]
async fn main() -> Result<()> {
    let endpoints = vec![
        "http://service-a.internal/health",
        "http://service-b.internal/health",
        // ... imagine 1000 more endpoints
    ];

    // Create a connection-pooling HTTP client
    let client = Client::builder()
        .timeout(Duration::from_secs(5))
        .pool_idle_timeout(Duration::from_secs(15))
        .build()?;

    // JoinSet allows us to spawn tasks and collect their results safely
    let mut set = JoinSet::new();

    for url in endpoints {
        let client_clone = client.clone(); // Clones the Arc internally, very cheap
        
        // Spawn a lightweight asynchronous task
        set.spawn(async move {
            let resp = client_clone.get(url).send().await;
            match resp {
                Ok(r) if r.status().is_success() => println!("✅ {} is UP", url),
                Ok(r) => println!("⚠️ {} returned {}", url, r.status()),
                Err(e) => println!("❌ {} FAILED: {}", url, e),
            }
        });
    }

    // Await completion of all spawned tasks
    while let Some(res) = set.join_next().await {
        // Handle potential panic within the spawned task
        if let Err(e) = res {
            eprintln!("Task panicked: {:?}", e);
        }
    }

    Ok(())
}

Code Annotations & Architecture

  • #[tokio::main]: A macro that sets up the multi-threaded Tokio runtime. It converts the async main function into a synchronous one that starts the executor.
  • Client::builder(): We instantiate the HTTP client outside the loop. reqwest::Client internally uses an Arc (Atomic Reference Counted pointer) and a connection pool.
  • client.clone(): Because of the Arc, cloning the client is virtually free. We do this to pass a handle into the async move block.
  • JoinSet::new(): A collection provided by Tokio specifically designed for spawning and awaiting large numbers of tasks. It's safer and cleaner than using raw tokio::spawn and pushing handles into a Vec, as it automatically aborts pending tasks if the set is dropped.
  • set.spawn(async move { ... }): This does not create an OS thread. It creates a lightweight green thread. Tokio will multiplex thousands of these tasks across a small pool of worker threads. When send().await is called, the task yields back to the executor, freeing the thread to run another task while waiting for the network I/O.

This CLI binary will compile to a few megabytes, require zero dependencies on the target host (no Python runtime or pip installs), and will complete 1,000 HTTP requests in roughly the time it takes the slowest single endpoint to respond.

Is your AI agent's infrastructure secure and reliable?

Book a Free 15-Min Technical Audit
Hire Me