forked from herocode/horus
fix coordinator compilation
This commit is contained in:
@@ -11,10 +11,13 @@ use std::hash::{Hash, Hasher};
|
||||
use tokio::sync::{Mutex, Semaphore};
|
||||
|
||||
use crate::{
|
||||
clients::{Destination, MyceliumClient, MyceliumTransport, SupervisorClient, SupervisorHub},
|
||||
models::{Job, JobStatus, Message, MessageStatus, ScriptType, TransportStatus},
|
||||
models::{Job, JobStatus, Message, MessageStatus, TransportStatus},
|
||||
service::AppService,
|
||||
};
|
||||
use hero_supervisor_openrpc_client::{
|
||||
SupervisorClient,
|
||||
transports::{Destination, MyceliumClient, MyceliumTransport, SupervisorHub},
|
||||
};
|
||||
use tracing::{error, info};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -197,44 +200,64 @@ async fn deliver_one(
|
||||
|
||||
// Load message
|
||||
let msg: Message = service.load_message(context_id, caller_id, id).await?;
|
||||
// Embedded job id (if any)
|
||||
let job_id_opt: Option<u32> = msg.job.first().map(|j| j.id);
|
||||
|
||||
// Determine routing from FlowNode.supervisor_url if available
|
||||
let supervisor_url = if !msg.nodes.is_empty() {
|
||||
// Use FlowNode routing (new architecture)
|
||||
msg.nodes[0].supervisor_url.clone()
|
||||
} else {
|
||||
// Fallback: get first available runner (legacy)
|
||||
let runners = service.scan_runners(context_id).await?;
|
||||
let Some(runner) = runners.into_iter().next() else {
|
||||
let log = format!(
|
||||
"No runners available in context {} for message {}",
|
||||
context_id, msg_key
|
||||
);
|
||||
let _ = service
|
||||
.append_message_logs(context_id, caller_id, id, vec![log.clone()])
|
||||
.await;
|
||||
let _ = service
|
||||
.update_message_status(context_id, caller_id, id, MessageStatus::Error)
|
||||
.await;
|
||||
return Err(log.into());
|
||||
};
|
||||
|
||||
// Build URL from runner
|
||||
if !runner.pubkey.trim().is_empty() {
|
||||
format!("mycelium://{}", runner.pubkey)
|
||||
} else {
|
||||
format!("http://{}", runner.address)
|
||||
}
|
||||
};
|
||||
|
||||
// Determine routing script_type
|
||||
let desired: ScriptType = determine_script_type(&msg);
|
||||
|
||||
// Discover runners and select a matching one
|
||||
let runners = service.scan_runners(context_id).await?;
|
||||
let Some(runner) = runners.into_iter().find(|r| r.script_type == desired) else {
|
||||
let log = format!(
|
||||
"No runner with script_type {:?} available in context {} for message {}",
|
||||
desired, context_id, msg_key
|
||||
);
|
||||
let _ = service
|
||||
.append_message_logs(context_id, caller_id, id, vec![log.clone()])
|
||||
.await;
|
||||
let _ = service
|
||||
.update_message_status(context_id, caller_id, id, MessageStatus::Error)
|
||||
.await;
|
||||
return Err(log.into());
|
||||
// Parse supervisor_url to determine destination
|
||||
// Format: "mycelium://<pubkey>" or "http://<address>" or just "<address>"
|
||||
let dest = if supervisor_url.starts_with("mycelium://") {
|
||||
let pubkey = supervisor_url.strip_prefix("mycelium://").unwrap_or("");
|
||||
Destination::Pk(pubkey.to_string())
|
||||
} else {
|
||||
// Extract address (strip http:// or https:// if present)
|
||||
let address_str = supervisor_url
|
||||
.strip_prefix("http://")
|
||||
.or_else(|| supervisor_url.strip_prefix("https://"))
|
||||
.unwrap_or(&supervisor_url);
|
||||
|
||||
// Parse IP address (strip port if present)
|
||||
let ip_str = address_str.split(':').next().unwrap_or(address_str);
|
||||
let ip_addr = ip_str.parse().unwrap_or_else(|_| {
|
||||
// Default to localhost if parsing fails
|
||||
std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1))
|
||||
});
|
||||
Destination::Ip(ip_addr)
|
||||
};
|
||||
|
||||
// Build SupervisorClient
|
||||
let dest = if !runner.pubkey.trim().is_empty() {
|
||||
Destination::Pk(runner.pubkey.clone())
|
||||
} else {
|
||||
Destination::Ip(runner.address)
|
||||
};
|
||||
// Keep clones for poller usage
|
||||
let dest_for_poller = dest.clone();
|
||||
let topic_for_poller = cfg.topic.clone();
|
||||
let secret_for_poller = runner.secret.clone();
|
||||
let client = cache
|
||||
.get_or_create(
|
||||
sup_hub.clone(),
|
||||
dest.clone(),
|
||||
cfg.topic.clone(),
|
||||
runner.secret.clone(),
|
||||
None, // TODO: Get secret from runner or config
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -244,11 +267,44 @@ async fn deliver_one(
|
||||
|
||||
// Send via the new client API
|
||||
// The transport handles message correlation internally
|
||||
let _result = if method == "job.run" {
|
||||
let job_result = if method == "job.run" {
|
||||
if let Some(j) = msg.job.first() {
|
||||
// Use typed job_run method
|
||||
let job = serde_json::from_value(job_to_json(j)?)?;
|
||||
client.job_run(job, None).await?;
|
||||
let result = client.job_run(job, None).await;
|
||||
|
||||
// Update node status based on result
|
||||
if !msg.nodes.is_empty() {
|
||||
let node_id = msg.nodes[0].id;
|
||||
let flow_id = msg.flow_id;
|
||||
|
||||
match &result {
|
||||
Ok(_) => {
|
||||
// Job completed successfully
|
||||
let _ = service
|
||||
.update_node_status_unchecked(
|
||||
context_id,
|
||||
flow_id,
|
||||
node_id,
|
||||
crate::dag::NodeStatus::Completed,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(_) => {
|
||||
// Job failed
|
||||
let _ = service
|
||||
.update_node_status_unchecked(
|
||||
context_id,
|
||||
flow_id,
|
||||
node_id,
|
||||
crate::dag::NodeStatus::Failed,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result?;
|
||||
serde_json::Value::Null
|
||||
} else {
|
||||
// Generic call - not supported in new API, would need custom implementation
|
||||
@@ -277,19 +333,16 @@ async fn deliver_one(
|
||||
.update_message_status(context_id, caller_id, id, MessageStatus::Acknowledged)
|
||||
.await?;
|
||||
|
||||
// For job.run, mark the job as dispatched
|
||||
// Log job completion
|
||||
if method == "job.run" {
|
||||
if let Some(job_id) = msg.job.first().map(|j| j.id) {
|
||||
let _ = service
|
||||
.update_job_status_unchecked(context_id, caller_id, job_id, JobStatus::Dispatched)
|
||||
.await;
|
||||
if let Some(job_id) = msg.job.first().map(|j| j.id.parse::<u32>().unwrap_or(0)) {
|
||||
let _ = service
|
||||
.append_message_logs(
|
||||
context_id,
|
||||
caller_id,
|
||||
id,
|
||||
vec![format!(
|
||||
"Supervisor reply for job {}: job_queued (processed synchronously)",
|
||||
"Job {} completed successfully",
|
||||
job_id
|
||||
)],
|
||||
)
|
||||
@@ -304,13 +357,7 @@ async fn deliver_one(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn determine_script_type(msg: &Message) -> ScriptType {
|
||||
// Prefer embedded job's script_type if available, else fallback to message.message_type
|
||||
match msg.job.first() {
|
||||
Some(j) => j.script_type.clone(),
|
||||
None => msg.message_type.clone(),
|
||||
}
|
||||
}
|
||||
// Removed determine_executor - routing now based on FlowNode.supervisor_url
|
||||
|
||||
fn build_params(msg: &Message) -> Result<Value, Box<dyn std::error::Error + Send + Sync>> {
|
||||
// Minimal mapping:
|
||||
|
||||
Reference in New Issue
Block a user