swactor/crates/mvp-system/src/vastai_offer_preview.rs

80 lines
2.3 KiB
Rust
Raw Normal View History

pub use swactor_vastai::SelectionPolicy;
use swactor_vastai::{Offer, VastClient};
#[derive(Clone, Debug, PartialEq)]
pub struct OfferPreview {
pub offer_id: u64,
pub host_id: Option<u64>,
pub gpu_name: String,
pub gpu_ram_mb: Option<u64>,
pub dollars_per_hour: f64,
}
impl OfferPreview {
pub fn from_offer(offer: Offer) -> Self {
Self {
offer_id: offer.id,
host_id: offer.host_id,
gpu_name: offer.gpu_name,
gpu_ram_mb: offer.gpu_ram.map(|gb| (gb * 1024.0).round() as u64),
dollars_per_hour: offer.dph_total,
}
}
}
pub trait OfferPreviewer {
fn preview(&self, api_key: &str, policy: &SelectionPolicy) -> Result<OfferPreview, String>;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct VastAiOfferPreviewer;
impl OfferPreviewer for VastAiOfferPreviewer {
fn preview(&self, api_key: &str, policy: &SelectionPolicy) -> Result<OfferPreview, String> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| format!("vastai offer preview runtime: {e}"))?;
let client = VastClient::new(api_key.to_owned());
let offers = runtime.block_on(client.search_offers(policy, 1))?;
let offer = offers
.into_iter()
.next()
.ok_or_else(|| "no Vast.ai offers available".to_owned())?;
Ok(OfferPreview::from_offer(offer))
}
}
#[cfg(test)]
mod tests {
use super::*;
use swactor_vastai::Offer;
#[test]
fn vastai_offer_preview_preserves_offer_identity_price_and_vram_megabytes() {
let preview = OfferPreview::from_offer(Offer {
id: 42,
gpu_name: "RTX 4090".to_owned(),
dph_total: 0.375,
gpu_ram: Some(23.5),
feat: successful 8 stage pipeline parallel run, more metrics Complete an 8-stage pipeline-parallel run over VastAI by provisioning stages high-to-low, adding per-stage/per-step metrics, host anti-colocation, and provider state-timeout guardrails. - orchestrator_app: select the next weight-load stage by max index (provision stages high-to-low for parallel spread), add a throttled "loaded N of M; waiting on stage X" stage_provision_wait headline, and surface min_compute_cap/state_timeout_secs in the config dump. - orchestrator_app: enrich pipeline_token_in/out and tokenizer_decode events with token_count/token_ids/generated_index. - worker_node: add timing metrics across the data path (helper_execute_ms, egress_ring_read_ms, send_ms, ingress_ring_write_ms, object_load_ms), refactor take_complete_ingress_record into IngressRecordBytes (object_id/sequence/extent/flags), and emit a new object_loaded event. - vastai_provisioning: track leased host_ids and blacklist already-leased hosts in later ProvisionRequests so stages don't co-locate, and tag SSH-bootstrap retry logs with the attempt number. - tools/vastai: add min_compute_cap (PP_MIN_COMPUTE_CAP) filter/search query and a LifecyclePolicy state_timeout (PP_STATE_TIMEOUT_SECS) that fails instances stuck in a non-running status instead of polling forever. - xtask: raise the check timeout to 1800s/30s grace, drop --skip-rebuild for VastAI, aggregate per-stage StepExecuted metrics, add a vastai summary section, and write failure artifacts on abort. Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
2026-07-25 16:04:57 +00:00
compute_cap: 890,
geolocation: Some("US".to_owned()),
inet_down_cost_per_tb: 0.0,
inet_up_cost_per_tb: 0.0,
host_id: Some(9001),
verification: Some("verified".to_owned()),
});
assert_eq!(
preview,
OfferPreview {
offer_id: 42,
host_id: Some(9001),
gpu_name: "RTX 4090".to_owned(),
gpu_ram_mb: Some(24_064),
dollars_per_hour: 0.375,
}
);
}
}