remove unused dep and move job out

This commit is contained in:
Timur Gordon
2025-09-01 16:21:31 +02:00
parent ef17d36300
commit 44b1dd4249
24 changed files with 2558 additions and 2739 deletions

View File

@@ -27,14 +27,10 @@
//! ```
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
use serde_json;
use uuid::Uuid;
// Import types from the main supervisor crate
#[cfg(not(target_arch = "wasm32"))]
use hero_supervisor::RunnerStatus;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
@@ -132,13 +128,12 @@ pub enum RunnerType {
PyRunner,
}
/// Process manager type for a runner
/// Process manager type for WASM compatibility
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ProcessManagerType {
/// Simple process manager for direct process spawning
Simple,
/// Tmux process manager for session-based management
Tmux(String), // session name
Tmux(String),
}
/// Configuration for an actor runner
@@ -157,16 +152,6 @@ pub struct RunnerConfig {
}
/// Job status enumeration
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum JobStatus {
Dispatched,
WaitingForPrerequisites,
Started,
Error,
Stopping,
Finished,
}
/// Job result response
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -186,30 +171,8 @@ pub struct JobStatusResponse {
pub completed_at: Option<String>,
}
/// Job structure for creating and managing jobs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Job {
/// Unique job identifier
pub id: String,
/// ID of the caller/client that created this job
pub caller_id: String,
/// Context ID for grouping related jobs
pub context_id: String,
/// Script content or payload to execute
pub payload: String,
/// Name of the specific runner/actor to execute this job
pub runner: String,
/// Name of the executor the runner will use to execute this job
pub executor: String,
/// Job execution timeout (in seconds)
pub timeout: u64,
/// Environment variables for job execution
pub env_vars: HashMap<String, String>,
/// Timestamp when the job was created
pub created_at: String,
/// Timestamp when the job was last updated
pub updated_at: String,
}
// Re-export Job types from shared crate
pub use hero_job::{Job, JobStatus, JobError, JobBuilder};
/// Process status wrapper for OpenRPC serialization (matches server response)
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -245,9 +208,21 @@ pub type ProcessStatus = ProcessStatusWrapper;
#[cfg(target_arch = "wasm32")]
pub type LogInfo = LogInfoWrapper;
/// Simple ProcessStatus type for native builds to avoid service manager dependency
#[cfg(not(target_arch = "wasm32"))]
pub type ProcessStatus = ProcessStatusWrapper;
/// Re-export types from supervisor crate for native builds
#[cfg(not(target_arch = "wasm32"))]
pub use hero_supervisor::{LogInfo, RunnerStatus as ProcessStatus};
pub use hero_supervisor::{ProcessManagerType, RunnerStatus};
#[cfg(not(target_arch = "wasm32"))]
pub use hero_supervisor::runner::LogInfo;
/// Type aliases for WASM compatibility
#[cfg(target_arch = "wasm32")]
pub type RunnerStatus = ProcessStatusWrapper;
#[cfg(target_arch = "wasm32")]
pub type LogInfo = LogInfoWrapper;
#[cfg(not(target_arch = "wasm32"))]
impl SupervisorClient {
@@ -425,31 +400,12 @@ impl SupervisorClient {
}
/// Get status of a specific runner
pub async fn get_runner_status(&self, actor_id: &str) -> ClientResult<ProcessStatus> {
#[cfg(target_arch = "wasm32")]
{
let status: ProcessStatusWrapper = self
.client
.request("get_runner_status", rpc_params![actor_id])
.await.map_err(|e| ClientError::JsonRpc(e))?;
Ok(status)
}
#[cfg(not(target_arch = "wasm32"))]
{
let status: ProcessStatusWrapper = self
.client
.request("get_runner_status", rpc_params![actor_id])
.await.map_err(|e| ClientError::JsonRpc(e))?;
// Convert wrapper to internal type for native builds
let internal_status = match status {
ProcessStatusWrapper::Running => RunnerStatus::Running,
ProcessStatusWrapper::Stopped => RunnerStatus::Stopped,
ProcessStatusWrapper::Starting => RunnerStatus::Starting,
ProcessStatusWrapper::Stopping => RunnerStatus::Stopping,
ProcessStatusWrapper::Error(msg) => RunnerStatus::Error(msg),
};
Ok(internal_status)
}
pub async fn get_runner_status(&self, actor_id: &str) -> ClientResult<RunnerStatus> {
let status: RunnerStatus = self
.client
.request("get_runner_status", rpc_params![actor_id])
.await.map_err(|e| ClientError::JsonRpc(e))?;
Ok(status)
}
/// Get logs for a specific runner
@@ -459,28 +415,11 @@ impl SupervisorClient {
lines: Option<usize>,
follow: bool,
) -> ClientResult<Vec<LogInfo>> {
#[cfg(target_arch = "wasm32")]
{
let logs: Vec<LogInfoWrapper> = self
.client
.request("get_runner_logs", rpc_params![actor_id, lines, follow])
.await.map_err(|e| ClientError::JsonRpc(e))?;
Ok(logs)
}
#[cfg(not(target_arch = "wasm32"))]
{
let logs: Vec<LogInfoWrapper> = self
.client
.request("get_runner_logs", rpc_params![actor_id, lines, follow])
.await.map_err(|e| ClientError::JsonRpc(e))?;
// Convert wrapper to internal type for native builds
let internal_logs = logs.into_iter().map(|log| hero_supervisor::LogInfo {
timestamp: log.timestamp,
level: log.level,
message: log.message,
}).collect();
Ok(internal_logs)
}
let logs: Vec<LogInfo> = self
.client
.request("get_runner_logs", rpc_params![actor_id, lines, follow])
.await.map_err(|e| ClientError::JsonRpc(e))?;
Ok(logs)
}
/// Queue a job to a specific runner
@@ -497,8 +436,7 @@ impl SupervisorClient {
Ok(())
}
/// Queue a job to a specific runner and wait for the result
/// This implements the proper Hero job protocol with BLPOP on reply queue
/// Queue a job and wait for completion
pub async fn queue_and_wait(&self, runner: &str, job: Job, timeout_secs: u64) -> ClientResult<Option<String>> {
let params = serde_json::json!({
"runner": runner,
@@ -512,6 +450,20 @@ impl SupervisorClient {
.await.map_err(|e| ClientError::JsonRpc(e))?;
Ok(result)
}
/// Run a job on a specific runner
pub async fn run_job(&self, secret: &str, job: Job) -> ClientResult<JobResult> {
let params = serde_json::json!({
"secret": secret,
"job": job
});
let result: JobResult = self
.client
.request("run_job", rpc_params![params])
.await.map_err(|e| ClientError::JsonRpc(e))?;
Ok(result)
}
/// Get job result by job ID
pub async fn get_job_result(&self, job_id: &str) -> ClientResult<Option<String>> {
@@ -523,31 +475,12 @@ impl SupervisorClient {
}
/// Get status of all runners
pub async fn get_all_runner_status(&self) -> ClientResult<Vec<(String, ProcessStatus)>> {
let statuses: Vec<(String, ProcessStatusWrapper)> = self
pub async fn get_all_runner_status(&self) -> ClientResult<Vec<(String, RunnerStatus)>> {
let statuses: Vec<(String, RunnerStatus)> = self
.client
.request("get_all_runner_status", rpc_params![])
.await.map_err(|e| ClientError::JsonRpc(e))?;
#[cfg(target_arch = "wasm32")]
{
Ok(statuses)
}
#[cfg(not(target_arch = "wasm32"))]
{
// Convert wrapper to internal type for native builds
let internal_statuses = statuses.into_iter().map(|(name, status)| {
let internal_status = match status {
ProcessStatusWrapper::Running => RunnerStatus::Running,
ProcessStatusWrapper::Stopped => RunnerStatus::Stopped,
ProcessStatusWrapper::Starting => RunnerStatus::Starting,
ProcessStatusWrapper::Stopping => RunnerStatus::Stopping,
ProcessStatusWrapper::Error(msg) => RunnerStatus::Error(msg),
};
(name, internal_status)
}).collect();
Ok(internal_statuses)
}
Ok(statuses)
}
/// Start all runners
@@ -569,31 +502,12 @@ impl SupervisorClient {
}
/// Get status of all runners (alternative method)
pub async fn get_all_status(&self) -> ClientResult<Vec<(String, ProcessStatus)>> {
let statuses: Vec<(String, ProcessStatusWrapper)> = self
pub async fn get_all_status(&self) -> ClientResult<Vec<(String, RunnerStatus)>> {
let statuses: Vec<(String, RunnerStatus)> = self
.client
.request("get_all_status", rpc_params![])
.await.map_err(|e| ClientError::JsonRpc(e))?;
#[cfg(target_arch = "wasm32")]
{
Ok(statuses)
}
#[cfg(not(target_arch = "wasm32"))]
{
// Convert wrapper to internal type for native builds
let internal_statuses = statuses.into_iter().map(|(name, status)| {
let internal_status = match status {
ProcessStatusWrapper::Running => RunnerStatus::Running,
ProcessStatusWrapper::Stopped => RunnerStatus::Stopped,
ProcessStatusWrapper::Starting => RunnerStatus::Starting,
ProcessStatusWrapper::Stopping => RunnerStatus::Stopping,
ProcessStatusWrapper::Error(msg) => RunnerStatus::Error(msg),
};
(name, internal_status)
}).collect();
Ok(internal_statuses)
}
Ok(statuses)
}
/// Add a secret to the supervisor
@@ -683,129 +597,6 @@ impl SupervisorClient {
}
}
/// Builder for creating jobs with a fluent API
pub struct JobBuilder {
caller_id: String,
context_id: String,
payload: String,
runner: String,
executor: String,
timeout: u64, // timeout in seconds
env_vars: HashMap<String, String>,
}
impl JobBuilder {
/// Create a new job builder
pub fn new() -> Self {
Self {
caller_id: "".to_string(),
context_id: "".to_string(),
payload: "".to_string(),
runner: "".to_string(),
executor: "".to_string(),
timeout: 300, // 5 minutes default
env_vars: HashMap::new(),
}
}
/// Set the caller ID for this job
pub fn caller_id(mut self, caller_id: impl Into<String>) -> Self {
self.caller_id = caller_id.into();
self
}
/// Set the context ID for this job
pub fn context_id(mut self, context_id: impl Into<String>) -> Self {
self.context_id = context_id.into();
self
}
/// Set the payload (script content) for this job
pub fn payload(mut self, payload: impl Into<String>) -> Self {
self.payload = payload.into();
self
}
/// Set the executor for this job
pub fn executor(mut self, executor: impl Into<String>) -> Self {
self.executor = executor.into();
self
}
/// Set the runner name for this job
pub fn runner(mut self, runner: impl Into<String>) -> Self {
self.runner = runner.into();
self
}
/// Set the timeout for job execution (in seconds)
pub fn timeout(mut self, timeout: u64) -> Self {
self.timeout = timeout;
self
}
/// Set a single environment variable
pub fn env_var(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.env_vars.insert(key.into(), value.into());
self
}
/// Set multiple environment variables from a HashMap
pub fn env_vars(mut self, env_vars: HashMap<String, String>) -> Self {
self.env_vars = env_vars;
self
}
/// Build the job
pub fn build(self) -> ClientResult<Job> {
if self.caller_id.is_empty() {
return Err(ClientError::Server {
message: "caller_id is required".to_string(),
});
}
if self.context_id.is_empty() {
return Err(ClientError::Server {
message: "context_id is required".to_string(),
});
}
if self.payload.is_empty() {
return Err(ClientError::Server {
message: "payload is required".to_string(),
});
}
if self.runner.is_empty() {
return Err(ClientError::Server {
message: "runner is required".to_string(),
});
}
if self.executor.is_empty() {
return Err(ClientError::Server {
message: "executor is required".to_string(),
});
}
let now = chrono::Utc::now().to_rfc3339();
Ok(Job {
id: Uuid::new_v4().to_string(),
caller_id: self.caller_id,
context_id: self.context_id,
payload: self.payload,
runner: self.runner,
executor: self.executor,
timeout: self.timeout,
env_vars: self.env_vars,
created_at: now.clone(),
updated_at: now,
})
}
}
impl Default for JobBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {