Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/server/src/provider/Drivers/AntigravityDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ import {
import type * as AcpSessionRuntime from "@t3tools/provider-acp/server/AcpSessionRuntime";
import type { ServerProviderDraft } from "@t3tools/provider-core/server/snapshotProbe";
import {
removeAntigravityRuntimeTempDirs,
removeAntigravitySessionFiles,
retireAntigravityRuntimeTempDirs,
} from "../acp/AntigravitySessionFiles.ts";
import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";
import * as ProviderContinuationRequests from "@t3tools/provider-core/server/ProviderContinuationRequests";
Expand Down Expand Up @@ -150,9 +150,11 @@ export const AntigravityDriver: ProviderDriver<
directories.runtimeTemp,
path.join(profileDirectory, "antigravity-acp", "tmp"),
]) {
yield* removeAntigravityRuntimeTempDirs(directory).pipe(
const removeRetired = yield* retireAntigravityRuntimeTempDirs(directory).pipe(
Effect.provideService(FileSystem.FileSystem, fileSystem),
Effect.provideService(Path.Path, path),
);
yield* Effect.forkScoped(removeRetired);
}
const continuationIdentity = defaultProviderContinuationIdentity({
driverKind: DRIVER,
Expand Down
64 changes: 64 additions & 0 deletions apps/server/src/provider/acp/AntigravitySessionFiles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as NodeServices from "@effect/platform-node/NodeServices";
import { expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Path from "effect/Path";
import * as PlatformError from "effect/PlatformError";

import { retireAntigravityRuntimeTempDirs } from "./AntigravitySessionFiles.ts";

it.layer(NodeServices.layer)("retireAntigravityRuntimeTempDirs", (it) => {
it.effect("moves leftovers aside at once and deletes them, plus older retirees, later", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const parent = yield* fs.makeTempDirectoryScoped();
const runtimeTemp = path.join(parent, "abc123");
const orphan = path.join(runtimeTemp, "run-orphan", "_MEI123");
yield* fs.makeDirectory(orphan, { recursive: true });
yield* fs.writeFileString(path.join(orphan, "payload.bin"), "stale");
yield* fs.makeDirectory(path.join(parent, "abc123.old-unfinished", "runtime"), {
recursive: true,
});
yield* fs.makeDirectory(path.join(parent, "other-instance"));

const removeRetired = yield* retireAntigravityRuntimeTempDirs(runtimeTemp);
expect(yield* fs.exists(runtimeTemp)).toBe(false);
const retired = (yield* fs.readDirectory(parent)).filter((entry) =>
entry.startsWith("abc123.old-"),
);
expect(retired).toHaveLength(2);

yield* removeRetired;
expect((yield* fs.readDirectory(parent)).toSorted()).toEqual(["other-instance"]);
}).pipe(Effect.scoped),
);

it.effect(
"deletes leftovers inline when they cannot be moved aside, such as on a full disk",
() =>
Effect.gen(function* () {
const removed: Array<string> = [];
const fs = FileSystem.makeNoop({
exists: () => Effect.succeed(true),
makeTempDirectory: () =>
Effect.fail(
PlatformError.systemError({
_tag: "Unknown",
module: "FileSystem",
method: "makeTempDirectory",
description: "ENOSPC",
}),
),
remove: (path) => Effect.sync(() => void removed.push(path)),
readDirectory: () => Effect.succeed([]),
});

const removeRetired = yield* retireAntigravityRuntimeTempDirs(
"/state/antigravity-tmp/abc123",
).pipe(Effect.provideService(FileSystem.FileSystem, fs));
yield* removeRetired;
expect(removed).toEqual(["/state/antigravity-tmp/abc123"]);
}),
);
});
34 changes: 28 additions & 6 deletions apps/server/src/provider/acp/AntigravitySessionFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,35 @@ export const removeAntigravitySessionFiles = Effect.fn("removeAntigravitySession
Effect.catch(() => Effect.logWarning("Could not remove temporary Antigravity session files.")),
);

/** Sweep only private runtimes before launch; Windows does not protect live extracted data files from deletion. */
export const removeAntigravityRuntimeTempDirs = Effect.fn("removeAntigravityRuntimeTempDirs")(
const warnRuntimeTempLeftovers = Effect.logWarning(
"Could not remove leftover Antigravity runtime temp files.",
);

/**
* Sweep only private runtimes before launch; Windows does not protect live extracted data files from deletion.
* Moves leftovers aside and returns their slow deletion (seconds on Windows) to run off the startup path.
*/
export const retireAntigravityRuntimeTempDirs = Effect.fn("retireAntigravityRuntimeTempDirs")(
function* (tempDirectory: string) {
const fs = yield* FileSystem.FileSystem;
yield* fs.remove(tempDirectory, { recursive: true, force: true });
const path = yield* Path.Path;
const parent = path.dirname(tempDirectory);
const prefix = `${path.basename(tempDirectory)}.old-`;
if (yield* fs.exists(tempDirectory)) {
yield* fs.makeTempDirectory({ directory: parent, prefix }).pipe(
Effect.flatMap((retired) => fs.rename(tempDirectory, path.join(retired, "runtime"))),
Effect.catch(() => fs.remove(tempDirectory, { recursive: true, force: true })),
);
}
const entries = yield* fs.readDirectory(parent).pipe(Effect.orElseSucceed(() => []));
return Effect.forEach(
entries.filter((entry) => entry.startsWith(prefix)),
(entry) =>
fs
.remove(path.join(parent, entry), { recursive: true, force: true })
.pipe(Effect.catch(() => warnRuntimeTempLeftovers)),
{ discard: true },
);
},
Effect.catch(() =>
Effect.logWarning("Could not remove leftover Antigravity runtime temp files."),
),
Effect.catch(() => warnRuntimeTempLeftovers.pipe(Effect.as(Effect.void))),
);
Loading