.. | ||
examples | ||
src | ||
tests | ||
.gitignore | ||
ARCHITECTURE.md | ||
Cargo.lock | ||
Cargo.toml | ||
circles.json | ||
README.md |
Circle Launcher
Crate for launching and managing circle workers and the circles ws server.
Features
- Single-server multi-circle architecture: One WebSocket server handles all circles via path-based routing
- Dual operation modes: Direct spawning or service manager integration
- Initialization scripts: Send Rhai scripts to workers on startup
- Service management: Automatic restart and background operation support
- Cross-platform: macOS (launchctl) and Linux (systemd) support
- Service cleanup: Automatic cleanup of background services on exit
Installation
Build the launcher:
cargo build --release --bin launcher
Usage
Basic Syntax
launcher [OPTIONS] -c <CIRCLE>...
Circle Configuration Format
Circles are specified using the -c/--circle
option with the format:
public_key[:init_script.rhai]
public_key
: secp256k1 public key in hex format (required)init_script.rhai
: Optional initialization script to send to the worker
Examples
Development Mode (Direct Spawning)
# Single circle without initialization script
launcher -c 02a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4
# Multiple circles with initialization scripts
launcher -c 02a1b2c3d4e5f6a7...d4:setup.rhai -c 03b2c3d4e5f6a7...e5:config.rhai
# Mixed configuration (some with scripts, some without)
launcher -c 02a1b2c3d4e5f6a7...d4:init.rhai -c 03b2c3d4e5f6a7...e5
Production Mode (Service Manager)
# Using service manager with worker binary
launcher --use-service-manager --worker-binary ./target/release/worker \
-c 02a1b2c3d4e5f6a7...d4:prod_init.rhai \
-c 03b2c3d4e5f6a7...e5
# Service manager without initialization scripts
launcher --use-service-manager --worker-binary /usr/local/bin/worker \
-c 02a1b2c3d4e5f6a7...d4 \
-c 03b2c3d4e5f6a7...e5
Command Line Options
Option | Short | Description | Default |
---|---|---|---|
--circle |
-c |
Circle configuration: public_key[:init_script.rhai] |
Required |
--port |
-p |
WebSocket server port | 8080 |
--redis-url |
Redis connection URL | redis://127.0.0.1:6379 |
|
--enable-auth |
Enable WebSocket authentication | false | |
--use-service-manager |
Use service manager instead of direct spawning | false | |
--worker-binary |
Path to worker binary (required with service manager) | None | |
--debug |
-d |
Enable debug logging | false |
--verbose |
-v |
Increase verbosity (can be used multiple times) | 0 |
Operation Modes
Direct Spawn Mode (Default)
In direct spawn mode, workers run as Tokio tasks within the launcher process:
- Pros: Simple setup, immediate shutdown, ideal for development
- Cons: Workers stop when launcher exits, no automatic restart
launcher -c 02a1b2c3d4e5f6a7...d4:init.rhai
Service Manager Mode
In service manager mode, workers are managed by the system service manager:
- Pros: Background operation, automatic restart, production-ready
- Cons: Requires worker binary, platform-specific setup
launcher --use-service-manager --worker-binary ./target/release/worker \
-c 02a1b2c3d4e5f6a7...d4:init.rhai
Service Manager Support
- macOS: Uses
launchctl
with launch agents - Linux: Uses
systemd
(implementation in progress)
Services are named: tf.ourworld.circles.circle-worker-{public_key}
Architecture
Single-Server Multi-Circle
The launcher creates one WebSocket server that handles multiple circles through path-based routing:
- Server URL:
ws://127.0.0.1:8080
- Circle URLs:
ws://127.0.0.1:8080/{circle_public_key}
- Worker Queues:
rhai_tasks:{circle_public_key}
Initialization Scripts
When a circle configuration includes an initialization script:
- Worker starts and connects to Redis
- Launcher waits 2 seconds for worker startup
- Launcher sends script content via RhaiDispatcher to worker's queue
- Worker executes the initialization script
Configuration
Environment Variables
RUST_LOG
: Controls logging level (auto-configured based on verbosity)PRESERVE_TASKS
: Preserve Redis tasks on worker shutdown
Data Directory
The launcher creates a ./launch_data
directory for:
- Worker databases:
circle_db_{public_key}.db
- Service configuration files (service manager mode)
Error Handling
Common error scenarios and solutions:
Error | Cause | Solution |
---|---|---|
"Invalid public key" | Malformed secp256k1 key | Verify key format (64 hex chars) |
"Worker binary path required" | Missing --worker-binary in service mode |
Provide path to worker executable |
"Failed to read init script" | Script file not found | Check script file path and permissions |
"Service already exists" | Service name conflict | Stop existing service or use different key |
Development
Building
# Debug build
cargo build --bin launcher
# Release build
cargo build --release --bin launcher
Testing
# Run with debug logging
RUST_LOG=debug cargo run --bin launcher -- -c 02a1b2c3d4e5f6a7...d4
# Test service manager mode
cargo run --bin launcher -- --use-service-manager \
--worker-binary ./target/debug/worker \
-c 02a1b2c3d4e5f6a7...d4:test.rhai
Troubleshooting
Worker Connection Issues
- Verify Redis is running on the specified URL
- Check worker binary exists and is executable
- Ensure public keys are valid secp256k1 format
Service Manager Issues
- Check service manager logs:
launchctl log show --predicate 'subsystem == "tf.ourworld.circles"'
- Verify worker binary permissions and dependencies
- Ensure working directory is accessible
Script Execution Issues
- Verify script file exists and is readable
- Check Redis connectivity for script transmission
- Monitor worker logs for script execution errors
Security Considerations
- Public Key Validation: All keys are validated as proper secp256k1 public keys
- Script Execution: Initialization scripts run with worker privileges
- Service Isolation: Each worker runs as a separate service in service manager mode
- Redis Security: Ensure Redis instance is properly secured in production
Performance
- Concurrent Workers: No hard limit on number of circles
- Resource Usage: Each worker consumes memory for database and Rhai engine
- Network: Single WebSocket server reduces port usage
- Startup Time: ~2 second delay for initialization script transmission
Service Cleanup
The launcher provides automatic cleanup functionality to stop and remove all circle-related services:
Automatic Cleanup
Examples automatically clean up services on exit:
# Run example - services are cleaned up automatically on exit or Ctrl+C
cargo run --example circle_launcher_example
Manual Cleanup
Clean up all circle services manually:
# Using the cleanup example
cargo run --example cleanup_example
# Or using the library function
use circles_launcher::cleanup_launcher;
cleanup_launcher().await?;
What Gets Cleaned Up
The cleanup function removes:
- All worker services (
circle-worker-{public_key}
) - WebSocket server service (
circle-ws-server
) - Associated service configuration files (plist files on macOS)
Signal Handling
Examples include signal handling for graceful cleanup:
- Ctrl+C: Triggers cleanup before exit
- Normal exit: Always runs cleanup before termination
- Error exit: Cleanup still runs to prevent orphaned services