mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 15:08:25 +00:00
refactor(sandbox): dedupe prune loops
This commit is contained in:
@@ -8,69 +8,80 @@ import {
|
|||||||
readRegistry,
|
readRegistry,
|
||||||
removeBrowserRegistryEntry,
|
removeBrowserRegistryEntry,
|
||||||
removeRegistryEntry,
|
removeRegistryEntry,
|
||||||
|
type SandboxBrowserRegistryEntry,
|
||||||
|
type SandboxRegistryEntry,
|
||||||
} from "./registry.js";
|
} from "./registry.js";
|
||||||
|
|
||||||
let lastPruneAtMs = 0;
|
let lastPruneAtMs = 0;
|
||||||
|
|
||||||
async function pruneSandboxContainers(cfg: SandboxConfig) {
|
type PruneableRegistryEntry = Pick<
|
||||||
const now = Date.now();
|
SandboxRegistryEntry,
|
||||||
|
"containerName" | "createdAtMs" | "lastUsedAtMs"
|
||||||
|
>;
|
||||||
|
|
||||||
|
function shouldPruneSandboxEntry(cfg: SandboxConfig, now: number, entry: PruneableRegistryEntry) {
|
||||||
const idleHours = cfg.prune.idleHours;
|
const idleHours = cfg.prune.idleHours;
|
||||||
const maxAgeDays = cfg.prune.maxAgeDays;
|
const maxAgeDays = cfg.prune.maxAgeDays;
|
||||||
if (idleHours === 0 && maxAgeDays === 0) {
|
if (idleHours === 0 && maxAgeDays === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const idleMs = now - entry.lastUsedAtMs;
|
||||||
|
const ageMs = now - entry.createdAtMs;
|
||||||
|
return (
|
||||||
|
(idleHours > 0 && idleMs > idleHours * 60 * 60 * 1000) ||
|
||||||
|
(maxAgeDays > 0 && ageMs > maxAgeDays * 24 * 60 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pruneSandboxRegistryEntries<TEntry extends PruneableRegistryEntry>(params: {
|
||||||
|
cfg: SandboxConfig;
|
||||||
|
read: () => Promise<{ entries: TEntry[] }>;
|
||||||
|
remove: (containerName: string) => Promise<void>;
|
||||||
|
onRemoved?: (entry: TEntry) => Promise<void>;
|
||||||
|
}) {
|
||||||
|
const now = Date.now();
|
||||||
|
if (params.cfg.prune.idleHours === 0 && params.cfg.prune.maxAgeDays === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const registry = await readRegistry();
|
const registry = await params.read();
|
||||||
for (const entry of registry.entries) {
|
for (const entry of registry.entries) {
|
||||||
const idleMs = now - entry.lastUsedAtMs;
|
if (!shouldPruneSandboxEntry(params.cfg, now, entry)) {
|
||||||
const ageMs = now - entry.createdAtMs;
|
continue;
|
||||||
if (
|
}
|
||||||
(idleHours > 0 && idleMs > idleHours * 60 * 60 * 1000) ||
|
try {
|
||||||
(maxAgeDays > 0 && ageMs > maxAgeDays * 24 * 60 * 60 * 1000)
|
await execDocker(["rm", "-f", entry.containerName], {
|
||||||
) {
|
allowFailure: true,
|
||||||
try {
|
});
|
||||||
await execDocker(["rm", "-f", entry.containerName], {
|
} catch {
|
||||||
allowFailure: true,
|
// ignore prune failures
|
||||||
});
|
} finally {
|
||||||
} catch {
|
await params.remove(entry.containerName);
|
||||||
// ignore prune failures
|
await params.onRemoved?.(entry);
|
||||||
} finally {
|
|
||||||
await removeRegistryEntry(entry.containerName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function pruneSandboxContainers(cfg: SandboxConfig) {
|
||||||
|
await pruneSandboxRegistryEntries<SandboxRegistryEntry>({
|
||||||
|
cfg,
|
||||||
|
read: readRegistry,
|
||||||
|
remove: removeRegistryEntry,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function pruneSandboxBrowsers(cfg: SandboxConfig) {
|
async function pruneSandboxBrowsers(cfg: SandboxConfig) {
|
||||||
const now = Date.now();
|
await pruneSandboxRegistryEntries<SandboxBrowserRegistryEntry>({
|
||||||
const idleHours = cfg.prune.idleHours;
|
cfg,
|
||||||
const maxAgeDays = cfg.prune.maxAgeDays;
|
read: readBrowserRegistry,
|
||||||
if (idleHours === 0 && maxAgeDays === 0) {
|
remove: removeBrowserRegistryEntry,
|
||||||
return;
|
onRemoved: async (entry) => {
|
||||||
}
|
const bridge = BROWSER_BRIDGES.get(entry.sessionKey);
|
||||||
const registry = await readBrowserRegistry();
|
if (bridge?.containerName === entry.containerName) {
|
||||||
for (const entry of registry.entries) {
|
await stopBrowserBridgeServer(bridge.bridge.server).catch(() => undefined);
|
||||||
const idleMs = now - entry.lastUsedAtMs;
|
BROWSER_BRIDGES.delete(entry.sessionKey);
|
||||||
const ageMs = now - entry.createdAtMs;
|
|
||||||
if (
|
|
||||||
(idleHours > 0 && idleMs > idleHours * 60 * 60 * 1000) ||
|
|
||||||
(maxAgeDays > 0 && ageMs > maxAgeDays * 24 * 60 * 60 * 1000)
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
await execDocker(["rm", "-f", entry.containerName], {
|
|
||||||
allowFailure: true,
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
// ignore prune failures
|
|
||||||
} finally {
|
|
||||||
await removeBrowserRegistryEntry(entry.containerName);
|
|
||||||
const bridge = BROWSER_BRIDGES.get(entry.sessionKey);
|
|
||||||
if (bridge?.containerName === entry.containerName) {
|
|
||||||
await stopBrowserBridgeServer(bridge.bridge.server).catch(() => undefined);
|
|
||||||
BROWSER_BRIDGES.delete(entry.sessionKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function maybePruneSandboxes(cfg: SandboxConfig) {
|
export async function maybePruneSandboxes(cfg: SandboxConfig) {
|
||||||
|
|||||||
Reference in New Issue
Block a user