A WASM job's placement names no image d7050703d2f4
The job has none; the line now starts with what the runner is doing. closes #323
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-10-26 02:36 UTC
- Signature
- ◈ sealed by Andy McCall
- Hash
d7050703d2f4c830367a32398629c87fe74160c58d1937c32b71eb313d29517f- Depends on
- 42fa95540468 501d8b268dd4 8501fd5815b9 a7e6e8e6094c b5668108487f c2be148cfe83
- Depended on by
- c26267b3aba6 1ec29691b67a dc5c64296b0a 1000b40a2629 b6dfcb61cf5e
- In bookmarks
- api-unknown-fields diffusion-pin-bookmark main proposal-list-fast
- In tags
- v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.6 v0.9.7 v0.9.8 v0.9.9
- Edits
- 4 atoms, 0 tree operations, 3 files
Browse the tree at this change
modified CHANGELOG.md +1 −0
| … | 3 unchanged lines |
||
| 4 | 4 | ||
| 5 | 5 | ## Unreleased |
|
| 6 | 6 | ||
| 7 | + | - **A WASM job's placement names no image (#323):** a job on the WASM tier was placed saying its runner "fetches the image from the hub"; it has none, so the line now starts with what the runner is doing (andymccall/windows-runner-demo run #1). |
|
| 7 | 8 | - **Runner updates: policy, test groups and the offer (#322):** Admin › Runners › Updates sets where runner builds come from (a repository whose releases carry `flow-linux-ARCH` files) and who takes them. Updates are off unless chosen; the site, an owner, a test group and a runner may each set updates on or off, a channel (`stable`, `canary` or a version), a window of hours (UTC) and dry run, and the nearest setting wins, each setting on its own. A test group is chosen runners or a percentage of the site's (or an owner's) runners, by a stable hash of each runner's id, so a share is the same machines every rollout and 10% sits inside 50%. `GET /api/v1/flow/runner/update` tells a runner its policy, where each setting came from, and the build to install (its BLAKE3, to check the download against); `POST` takes what the runner did, shown on the page and in the audit log. Pins OxygenFlow's main. |
|
| 8 | 9 | ||
| 9 | 10 | ## 0.9.5 (2026-10-26) |
|
| … | 335 unchanged lines |
modified crates/hub/src/flow.rs +9 −5
| … | 1109 unchanged lines |
||
| 1110 | 1110 | let waited = |
|
| 1111 | 1111 | HELD.lock().unwrap_or_else(|p| p.into_inner()).as_mut().and_then(|h| h.remove(&(hub_key.clone(), job.id))).map(|t| now - t); |
|
| 1112 | 1112 | let rootfs = rootfs_of(&job); |
|
| 1113 | - | let mut why = vec![if me_now.image_list().is_some_and(|have| have.contains(&rootfs)) { |
|
| 1114 | - | "holds the image".to_string() |
|
| 1115 | - | } else { |
|
| 1116 | - | "fetches the image from the hub".to_string() |
|
| 1117 | - | }]; |
|
| 1113 | + | // A WASM job has no image (#323), so nothing to hold or fetch. |
|
| 1114 | + | let mut why = Vec::new(); |
|
| 1115 | + | if !rootfs.is_empty() { |
|
| 1116 | + | why.push(if me_now.image_list().is_some_and(|have| have.contains(&rootfs)) { |
|
| 1117 | + | "holds the image".to_string() |
|
| 1118 | + | } else { |
|
| 1119 | + | "fetches the image from the hub".to_string() |
|
| 1120 | + | }); |
|
| 1121 | + | } |
|
| 1118 | 1122 | if let Some(kept) = slots.get(&job.id).and_then(|slot| cache_kept(&hub_key, me.id, slot)) { |
|
| 1119 | 1123 | why.insert( |
|
| 1120 | 1124 | 0, |
|
| … | 1919 unchanged lines |
modified crates/hub/tests/flow.rs +24 −0
| … | 6709 unchanged lines |
||
| 6710 | 6710 | assert!(page.contains("Test group canary removed"), "{page}"); |
|
| 6711 | 6711 | assert!(!ask(0).await.policy.updates, "back to the site's off"); |
|
| 6712 | 6712 | } |
|
| 6713 | + | ||
| 6714 | + | /// #323: a WASM job has no image, so its placement says nothing of one. |
|
| 6715 | + | #[tokio::test(flavor = "multi_thread")] |
|
| 6716 | + | async fn a_wasm_jobs_placement_names_no_image() { |
|
| 6717 | + | let h = hub().await; |
|
| 6718 | + | create(&h.app, "andy", "wasm").await; |
|
| 6719 | + | let work = tempfile::tempdir().unwrap(); |
|
| 6720 | + | let c = client(&format!("{}/andy/wasm", h.base), work.path()); |
|
| 6721 | + | write( |
|
| 6722 | + | work.path(), |
|
| 6723 | + | ".flow/pipeline.kdl", |
|
| 6724 | + | "schema-version 1\nsandbox \"w\" {\n runtime \"wasm\"\n}\njob \"count\" {\n sandbox \"w\"\n exec \"count.wasm\"\n}\n", |
|
| 6725 | + | ); |
|
| 6726 | + | write(work.path(), "count.wasm", "\0asm"); |
|
| 6727 | + | c.commit("A WASM job", &[]).unwrap(); |
|
| 6728 | + | assert!(c.push("origin", false).unwrap().iter().all(|r| r.ok)); |
|
| 6729 | + | runs_of(&h.app, "andy", "wasm").await; |
|
| 6730 | + | let (st, body) = |
|
| 6731 | + | call(&h.app, "POST", "/api/v1/flow/claim", Some("runner-secret"), Some(r#"{"runner":"test-1","runtimes":["wasm"]}"#.into())).await; |
|
| 6732 | + | assert_eq!(st, StatusCode::OK, "{body}"); |
|
| 6733 | + | let id = serde_json::from_str::<serde_json::Value>(&body).unwrap()["job_id"].as_i64().unwrap(); |
|
| 6734 | + | let placed = db::flow::job(&h.app.db, id).await.unwrap().unwrap().placed; |
|
| 6735 | + | assert!(placed.starts_with("idle") && !placed.contains("image"), "{placed}"); |
|
| 6736 | + | } |