The bed keeps its genesis warm
MESH_LAB_WARM=1 snapshots the post-genesis, both-nodes-enrolled state and restores it in seconds on later runs — refused, not silently rebuilt, when the commits have moved (src/warm.ts, the mechanism mesh.test.ts already uses and this session had ignored). Fresh stays the default. https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -34,6 +34,7 @@ import { destroy, exec, push } from "../../src/lifecycle/operate.ts";
|
||||
import { bootstrapBinaryPath, hostBinaryPath, HOST_PATH } from "../../src/lifecycle/place.ts";
|
||||
import { labIsUsable, destroyAll, foundationBundle } from "./harness.ts";
|
||||
import { genesis, type GenesisResult } from "./genesis.ts";
|
||||
import { keep, ready, returnTo } from "../../src/warm.ts";
|
||||
|
||||
const SCENARIO = "built-store-cross-node";
|
||||
const CONTROL = "anchor";
|
||||
@@ -50,6 +51,13 @@ const catalogDir = process.env["MESH_LAB_CATALOG"] ?? "";
|
||||
const source = process.env["MESH_LAB_SOURCE"] ?? "";
|
||||
const sourceRef = process.env["MESH_LAB_SOURCE_REF"] ?? "";
|
||||
const KEEP = !!process.env["MESH_LAB_KEEP"];
|
||||
/**
|
||||
* MESH_LAB_WARM=1: restore the post-genesis, both-nodes-enrolled state from a snapshot instead of
|
||||
* re-running the installer (minutes -> seconds), refused — not silently rebuilt — when the commits
|
||||
* it was built from have moved (src/warm.ts). Fresh stays the default: a run that must MEAN
|
||||
* something raises from nothing.
|
||||
*/
|
||||
const warming = process.env["MESH_LAB_WARM"] === "1";
|
||||
|
||||
function forgeUrl(repo: string): string {
|
||||
const override = process.env[`MESH_LAB_SOURCE_${repo.toUpperCase().replaceAll("-", "_")}`];
|
||||
@@ -151,6 +159,21 @@ async function waitForContainer(node: string, container: string, seconds = 300):
|
||||
|
||||
before(async () => {
|
||||
if (skip) return;
|
||||
if (warming) {
|
||||
const said = await ready(SCENARIO);
|
||||
if (said.use === "restore") {
|
||||
instanceId = said.instanceId;
|
||||
const seconds = await returnTo(instanceId);
|
||||
// A snapshot captures disk, not memory: the restore reboots. anchor's host is a systemd
|
||||
// service (genesis hostService) and comes back on its own; node2's was hand-started.
|
||||
await must(NODE, `pgrep -x mesh-host >/dev/null || (nohup ${HOST_PATH} run > /var/log/mesh-host.log 2>&1 & sleep 3)`);
|
||||
const back = (await on(CONTROL, `docker ps --format '{{.Names}}'`)).out;
|
||||
assert.match(back, /mesh-controller/, `the control plane did not come back after restore:\n${back}`);
|
||||
console.log(`warm: returned ${instanceId} to its post-genesis state in ${seconds.toFixed(1)}s`);
|
||||
return;
|
||||
}
|
||||
console.log(`warm: raising fresh — ${said.why}`);
|
||||
}
|
||||
const bed = await raise(loadScenario(`scenarios/${SCENARIO}.yml`), {
|
||||
onProgress: (m) => console.log(`raise: ${m}`),
|
||||
});
|
||||
@@ -188,9 +211,17 @@ before(async () => {
|
||||
const said = await must(NODE, `${HOST_PATH} enrol --token ${quote(token)}`);
|
||||
assert.match(said, new RegExp(`enrolled as ${NODE}`), said);
|
||||
await must(NODE, `nohup ${HOST_PATH} run > /var/log/mesh-host.log 2>&1 & sleep 3`);
|
||||
|
||||
// The expensive, deterministic part is done: genesis ran and both machines are enrolled. Keep it.
|
||||
if (warming) {
|
||||
const warm = await keep(SCENARIO, instanceId);
|
||||
console.log(`warm: ${warm.instanceId} kept, against ` +
|
||||
Object.entries(warm.against).map(([n, c]) => `${n} ${c}`).join(", "));
|
||||
}
|
||||
}, { timeout: 7_200_000 });
|
||||
|
||||
after(async () => {
|
||||
if (warming) { console.log(`warm — ${instanceId} stays; \`mesh-lab warm cool\` retires it`); return; }
|
||||
if (KEEP) { console.log(`MESH_LAB_KEEP set — leaving ${instanceId} standing`); return; }
|
||||
if (instanceId) await destroy(instanceId);
|
||||
await destroyAll(`${SCENARIO}-`);
|
||||
|
||||
Reference in New Issue
Block a user