swactor/crates/ci/src/runner.rs

85 lines
2.8 KiB
Rust
Raw Normal View History

2026-02-15 13:57:36 +00:00
//! RunnerSupervisor actor: manages SSH session and job execution on a spot instance.
//!
//! Spawned per-job by the Coordinator. Owns the connection to the spot instance.
use swactor::actor::{ActorAddress, ActorInterface, Ctx};
use crate::coordinator::CoordinatorMsg;
use crate::{JobComplete, JobFailure, JobProgress, JobSuccess, StartJob};
/// Messages the RunnerSupervisor can receive.
#[derive(Debug, Clone)]
pub enum RunnerMsg {
/// Begin executing the job (sent immediately after spawn via on_start).
Execute,
/// Simulated: job command output line.
OutputLine(String),
/// Simulated: job completed successfully.
SimComplete(Result<(), String>),
}
/// RunnerSupervisor actor state.
///
/// In real deployment, this would manage an SSH connection.
/// In simulation, job execution is driven by external messages.
pub struct RunnerSupervisor {
coordinator_addr: ActorAddress,
start_job: StartJob,
}
impl RunnerSupervisor {
pub fn new(coordinator_addr: ActorAddress, start_job: StartJob) -> Self {
Self {
coordinator_addr,
start_job,
}
}
}
impl ActorInterface for RunnerSupervisor {
type Incoming = RunnerMsg;
type Response = ();
fn on_start(&mut self, ctx: &Ctx) {
// In simulation, the sim harness will send SimComplete messages.
// In real deployment, this would initiate SSH connection + command execution.
let _ = ctx.send(ctx.self_addr(), RunnerMsg::Execute);
}
fn handle(&mut self, ctx: &Ctx, msg: RunnerMsg) {
match msg {
RunnerMsg::Execute => {
// In real mode, we'd SSH into the instance and run commands.
// In simulation, this is a no-op; SimComplete drives completion.
}
RunnerMsg::OutputLine(line) => {
let _ = ctx.send(
self.coordinator_addr,
CoordinatorMsg::JobProgress(JobProgress {
job_id: self.start_job.job_id.clone(),
output_line: line,
}),
);
}
RunnerMsg::SimComplete(result) => {
let complete = JobComplete {
job_id: self.start_job.job_id.clone(),
result: match result {
Ok(()) => Ok(JobSuccess),
Err(msg) => Err(JobFailure::CommandFailed {
exit_code: 1,
last_lines: vec![msg],
}),
},
artifacts: Vec::new(),
};
let _ = ctx.send(
self.coordinator_addr,
CoordinatorMsg::JobComplete(complete),
);
ctx.stop_self();
}
}
}
}