Timur Gordon a47157aa71 fix: keep OpenRPC ServerHandle alive to prevent server shutdown
The ServerHandle was being dropped immediately after spawning, causing the
OpenRPC server to shut down. Now we properly await handle.stopped() to keep
the server running.
2025-10-27 14:34:22 +01:00
2025-08-27 10:07:53 +02:00
2025-08-27 10:07:53 +02:00
2025-09-02 09:15:24 +02:00
2025-08-27 10:07:53 +02:00

Hero Supervisor

A Rust-based actor management system for the Hero ecosystem that provides unified process management, job queuing, and optional OpenRPC server integration.

Architecture Overview

The Hero Supervisor uses a clean, feature-gated architecture that separates library functionality from CLI/server features to avoid dependency cycles and maintain modularity.

hero-supervisor/
├── src/                    # Core library (no CLI dependencies)
│   ├── lib.rs             # Main library exports and documentation
│   ├── supervisor.rs      # Core supervisor logic and actor management
│   ├── runner.rs          # Runner implementation for actor process management
│   ├── job.rs            # Job data structures, builder pattern, and Redis key management
│   └── openrpc.rs        # OpenRPC server (feature-gated)
├── cmd/                   # CLI binaries

## Features

The crate uses Rust's feature system to provide conditional compilation:

- **`default`**: Includes CLI functionality
- **`cli`**: Enables the supervisor binary (included in default)

All OpenRPC functionality is now included by default for simplified deployment.

## Architecture

The Hero Supervisor uses a clean, simplified architecture with centralized resource management:

### Core Components

#### `SupervisorBuilder` → `Supervisor` → `SupervisorApp`
- **`SupervisorBuilder`**: Configures Redis URL, namespace, secrets, runners, and process manager
- **`Supervisor`**: Core engine that owns Redis client and process manager, manages runners centrally
- **`SupervisorApp`**: Main application that wraps supervisor and provides `start()` method for complete lifecycle management

### Key Design Decisions

- **Centralized Resources**: Supervisor exclusively owns Redis client and process manager (no per-runner instances)
- **Builder Pattern**: Flexible configuration through `SupervisorBuilder` with method chaining
- **Direct OpenRPC Integration**: RPC trait implemented directly on `Arc<Mutex<Supervisor>>` (no wrapper layers)
- **Simplified App**: `SupervisorApp::start()` handles everything - runners, OpenRPC server, graceful shutdown

## File Documentation

### Core Library Files

#### `src/lib.rs`
Main library entry point that exports `Supervisor`, `SupervisorBuilder`, `SupervisorApp`, and related types.

#### `src/supervisor.rs`
Core supervisor implementation with builder pattern. Manages runners, owns shared Redis client and process manager. Provides job queuing, runner lifecycle management, and status monitoring.

#### `src/app.rs`
Main application wrapper that provides `start()` method for complete lifecycle management. Handles OpenRPC server startup, graceful shutdown, and keeps the application running.

#### `src/runner.rs`
Simplified runner configuration and management. Contains `Runner` struct with configuration data only - no resource ownership. Integrates with supervisor's shared resources.

#### `src/job.rs`
Job data structures, builder pattern, and Redis key management. Defines `Job` struct with metadata, script content, and status tracking.

#### `src/client.rs`
Client implementation for job management operations. Provides Redis-based job storage, retrieval, status updates, and lifecycle management. Separates job operations from supervisor logic.

#### `src/openrpc.rs`
OpenRPC server implementation that exposes all supervisor functionality over JSON-RPC. Implements RPC trait directly on the supervisor for clean integration.

### Binary Files

#### `cmd/supervisor.rs`
Main supervisor binary that creates a supervisor using the builder pattern and starts the complete application with `app.start()`. The OpenRPC server is always enabled and starts automatically.

## Usage

### Running the Supervisor Binary

```bash
# Run with default (error) logging
cargo run --bin supervisor

# Run with info logging
RUST_LOG=info cargo run --bin supervisor

# Run with debug logging  
RUST_LOG=debug cargo run --bin supervisor

# Run with trace logging (very verbose)
RUST_LOG=trace cargo run --bin supervisor

# Run with specific module logging
RUST_LOG=hero_supervisor=debug cargo run --bin supervisor

Library Usage

use hero_supervisor::{SupervisorBuilder, SupervisorApp};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build supervisor with configuration
    let supervisor = SupervisorBuilder::new()
        .redis_url("redis://localhost:6379")
        .namespace("hero")
        .build()
        .await?;
    
    // Create and start the complete application
    let mut app = SupervisorApp::new(supervisor);
    app.start().await?;
    
    Ok(())
}

As a Dependency

[dependencies]
hero-supervisor = "0.1.0"

OpenRPC Server

The supervisor automatically starts an OpenRPC server on 127.0.0.1:3030 that exposes all supervisor functionality via JSON-RPC.

Available Methods

  • add_runner - Add a new actor/runner
  • remove_runner - Remove an actor/runner
  • list_runners - List all runner IDs
  • start_runner - Start a specific runner
  • stop_runner - Stop a specific runner
  • get_runner_status - Get status of a specific runner
  • get_runner_logs - Get logs for a specific runner
  • queue_job_to_runner - Queue a job to a specific runner
  • get_all_runner_status - Get status of all runners
  • start_all - Start all runners
  • stop_all - Stop all runners
  • get_all_status - Get status summary for all runners

Example JSON-RPC Call

curl -X POST -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"list_runners","id":1}' \
  http://127.0.0.1:3030

Development

Building

# Build everything (default includes CLI and OpenRPC)
cargo build

# Library only (minimal build)
cargo build --no-default-features

# With CLI (same as default)
cargo build --features cli

Testing

cargo test --all-features

Running

# Start supervisor with OpenRPC server
RUST_LOG=info cargo run --features openrpc

Dependencies

Core Dependencies

  • tokio - Async runtime
  • redis - Redis client for job queuing
  • serde - Serialization
  • log - Logging
  • sal-service-manager - Process management

Feature-Gated Dependencies

  • jsonrpsee - JSON-RPC server (openrpc feature)
  • anyhow - Error handling (openrpc feature)

Architecture Benefits

  1. No Cyclic Dependencies: Library and OpenRPC server are in the same crate, eliminating dependency cycles
  2. Feature-Gated: CLI and server functionality only compiled when needed
  3. Clean Separation: Library can be used independently without CLI dependencies
  4. Conditional Compilation: Rust's feature system ensures minimal dependencies for library users
  5. Single Binary: One supervisor binary with optional OpenRPC server integration

License

[Add your license information here]

Description
No description provided
Readme 1.2 MiB
Languages
Rust 87.3%
CSS 6.1%
Shell 3%
HTML 2.3%
Python 1.3%