mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
feat(orchestrator): read ORCHESTRATOR_PORT env var for configurable API port (#1113)
* feat(orchestrator): read ORCHESTRATOR_PORT env var for configurable API port The orchestrator internal API port was hardcoded to 50051 in two places (ContainerJobConfig and OrchestratorApi::start call), making it impossible to run multiple IronClaw instances on the same host — the second instance fails with "Address already in use". NETWORK_SECURITY.md already documents ORCHESTRATOR_PORT as configurable, and ContainerJobConfig.orchestrator_port is propagated to worker containers via IRONCLAW_ORCHESTRATOR_URL, but the env var was never actually read. Extract resolve_orchestrator_port() that reads ORCHESTRATOR_PORT and falls back to 50051. Includes tests for valid, invalid, and out-of-range values. * test: add ENV_LOCK mutex for env-var test serialization Address Gemini review: add std::sync::Mutex to serialize env var access across test threads. Keep unsafe blocks — required in Rust edition 2024 where std::env::set_var/remove_var are unsafe functions. --------- Co-authored-by: SMKRV <[email protected]>
This commit is contained in:
+49
-2
@@ -51,6 +51,15 @@ use crate::db::Database;
|
||||
use crate::llm::LlmProvider;
|
||||
use crate::secrets::SecretsStore;
|
||||
|
||||
/// Resolve the orchestrator port from the `ORCHESTRATOR_PORT` environment
|
||||
/// variable, falling back to 50051.
|
||||
fn resolve_orchestrator_port() -> u16 {
|
||||
std::env::var("ORCHESTRATOR_PORT")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(50051)
|
||||
}
|
||||
|
||||
/// Result of orchestrator setup, containing all handles needed by the agent.
|
||||
pub struct OrchestratorSetup {
|
||||
pub container_job_manager: Option<Arc<ContainerJobManager>>,
|
||||
@@ -101,11 +110,12 @@ pub async fn setup_orchestrator(
|
||||
let job_event_tx = Some(tx);
|
||||
|
||||
let token_store = TokenStore::new();
|
||||
let orchestrator_port = resolve_orchestrator_port();
|
||||
let job_config = ContainerJobConfig {
|
||||
image: config.sandbox.image.clone(),
|
||||
memory_limit_mb: config.sandbox.memory_limit_mb,
|
||||
cpu_shares: config.sandbox.cpu_shares,
|
||||
orchestrator_port: 50051,
|
||||
orchestrator_port,
|
||||
claude_code_api_key: std::env::var("ANTHROPIC_API_KEY").ok(),
|
||||
claude_code_oauth_token: crate::config::ClaudeCodeConfig::extract_oauth_token(),
|
||||
claude_code_model: config.claude_code.model.clone(),
|
||||
@@ -127,7 +137,7 @@ pub async fn setup_orchestrator(
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = OrchestratorApi::start(orchestrator_state, 50051).await {
|
||||
if let Err(e) = OrchestratorApi::start(orchestrator_state, orchestrator_port).await {
|
||||
tracing::error!("Orchestrator API failed: {}", e);
|
||||
}
|
||||
});
|
||||
@@ -151,3 +161,40 @@ pub async fn setup_orchestrator(
|
||||
docker_status,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Mutex;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Serialize access to `ORCHESTRATOR_PORT` env var across test threads.
|
||||
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
#[test]
|
||||
fn resolve_orchestrator_port_from_env() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
|
||||
// Safety: env-var mutation requires unsafe in edition 2024;
|
||||
// ENV_LOCK serializes concurrent access from other test threads.
|
||||
|
||||
// Absent env var → default 50051
|
||||
unsafe { std::env::remove_var("ORCHESTRATOR_PORT") };
|
||||
assert_eq!(resolve_orchestrator_port(), 50051);
|
||||
|
||||
// Valid custom port
|
||||
unsafe { std::env::set_var("ORCHESTRATOR_PORT", "50052") };
|
||||
assert_eq!(resolve_orchestrator_port(), 50052);
|
||||
|
||||
// Non-numeric value → fallback to default
|
||||
unsafe { std::env::set_var("ORCHESTRATOR_PORT", "not_a_port") };
|
||||
assert_eq!(resolve_orchestrator_port(), 50051);
|
||||
|
||||
// Out of u16 range → fallback to default
|
||||
unsafe { std::env::set_var("ORCHESTRATOR_PORT", "99999") };
|
||||
assert_eq!(resolve_orchestrator_port(), 50051);
|
||||
|
||||
// Cleanup
|
||||
unsafe { std::env::remove_var("ORCHESTRATOR_PORT") };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user