Runtime lifecycle
Suspend and resume the SDK runtime (e.g., when the host app moves to background) and query lifecycle state.
Overview
While running, the SDK keeps live resources in the host process — Hyperswarm sockets, Corestore handles, RAG corestore, registered download streams, and a request gate above handler dispatch. When the host app moves to background (mobile suspend, desktop minimize, daemon hibernation), holding those resources open wastes battery and can break sockets that are torn down by the OS.
suspend() pauses those resources and engages a lifecycle gate so non-lifecycle operations fail fast instead of hanging. resume() restores them when the app returns to foreground. state() is the source of truth for the current runtime state — useful for branching app logic without shadow-tracking suspend/resume locally.
suspend(), resume(), and state() are themselves never blocked by the gate, and all three are idempotent.
Functions
suspend()— call from the background handlerstate()— read"active" | "suspending" | "suspended" | "resuming"resume()— call from the foreground handler
For how to use each function, see SDK — API reference.
Lifecycle states
state() returns one of:
"active"— all SDK operations are accepted normally"suspending"—suspend()is in progress; non-lifecycle operations are already blocked"suspended"— runtime is paused; onlysuspend(),resume(),state()are accepted"resuming"—resume()is in progress; non-lifecycle operations are still blocked
A partial resume() failure leaves the runtime in "suspended" (not "active"), so callers can retry resume() without leaking the failed state.
Behavior while suspended
While runtime state is not "active", only suspend(), resume(), and state() are accepted. Any other request fails fast with LIFECYCLE_OPERATION_BLOCKED instead of hanging.
In-flight operations started before suspend() follow the matrix below:
| Operation | During suspend | After resume |
|---|---|---|
| P2P / Hyperdrive download | Stalls cleanly | Continues automatically |
| HTTP download | Bypass — bytes keep flowing | (Already flowing) |
Local native inference (e.g. completion()) | Runs to completion | n/a |
| Delegated reply RPC | Stalls | Auto-recovers (subject to delegate timeout) |
| Delegated stream RPC | Severed; consumer iterator hangs silently | Not recovered — re-issue after resume() |
New operation (e.g. completion(), loadModel()) | Throws LIFECYCLE_OPERATION_BLOCKED | Accepted |
Example
The following script loads a model, runs a completion, suspends the runtime, demonstrates that a new completion() is blocked while suspended, then resumes and runs another completion. state() is sampled at each step:
import { loadModel, LLAMA_3_2_1B_INST_Q4_0, completion, unloadModel, suspend, resume, state, } from "@qvac/sdk";
try {
// Load a model
const modelId = await loadModel({
modelSrc: LLAMA_3_2_1B_INST_Q4_0,
modelType: "llm",
onProgress: (progress) => {
console.log(progress);
},
});
console.log("✅ Model loaded\n");
console.log(`📊 Lifecycle state: ${await state()}\n`);
// Run a completion before suspending
console.log("--- Completion before suspend ---");
const result1 = completion({
modelId,
history: [{ role: "user", content: "Say hello in one word" }],
stream: true,
});
for await (const token of result1.tokenStream) {
process.stdout.write(token);
}
console.log("\n");
// Suspend all networking and storage (e.g. app going to background)
console.log("⏸️ Suspending...");
await suspend();
console.log(`📊 Lifecycle state: ${await state()}\n`);
try {
await completion({
modelId,
history: [{ role: "user", content: "This should fail" }],
stream: false,
}).text;
}
catch (error) {
const name = error.name;
if (name === "LIFECYCLE_OPERATION_BLOCKED") {
console.log(`🚫 Operation blocked while suspended (${name})`);
}
else {
throw error;
}
}
// Simulate time in background
console.log("\n💤 Simulating 3 seconds in background...");
await new Promise((resolve) => setTimeout(resolve, 3000));
// Resume when returning to foreground
console.log("▶️ Resuming...");
await resume();
console.log(`📊 Lifecycle state: ${await state()}\n`);
// Run another completion after resuming
console.log("--- Completion after resume ---");
const result2 = completion({
modelId,
history: [{ role: "user", content: "Say goodbye in one word" }],
stream: true,
});
for await (const token of result2.tokenStream) {
process.stdout.write(token);
}
console.log("\n");
await unloadModel({ modelId });
console.log("✅ Model unloaded");
process.exit(0);
}
catch (error) {
console.error("❌ Error:", error);
process.exit(1);
}Tip: all examples throughout this documentation are self-contained and runnable. For instructions on how to run them, see SDK quickstart.