perf(gateway): cache compiled entry startup in source checkouts (#170514)

Select compile-cache policy from the executing entry file instead of probing the installation for source checkout markers. Preserve TypeScript source respawn behavior and reuse the existing build-scoped cache owner for compiled entries.

In a 5,000-session synthetic Linux fixture, repeated process-start to readiness fell from 8.31s to 7.04s; bootstrap fell from 2.96s to 2.44s. Focused entry, diagnostic and compiled-helper tests passed, with independent review clean. Cold-cache population remains a separate one-time cost.
This commit is contained in:
Peter Steinberger authored and GitHub committed 2026-10-12 19:03:37 -07:00
1 parent ebf0a83c6b
commit e517de8ca2
7 files changed
+49 -36

No files matched your search

+1 -1
View File
@@ -77,7 +77,7 @@ Gateway config reload watches the active config file path (resolved from profile
### Module compile cache
The packaged CLI and the compiled `dist/index.js` entry automatically enable
The packaged CLI and the compiled `dist/entry.js` and `dist/index.js` entries automatically enable
Node's on-disk module compile cache. This includes compiled source deployments
that retain their Git checkout. Cache entries live outside the release directory,
under the operating system's temporary directory by default. Set
+30 -17
View File
@@ -143,7 +143,9 @@ describe("entry compile cache", () => {
async function markSourceCheckout() {
await fs.mkdir(path.join(root, "src"), { recursive: true });
await fs.writeFile(path.join(root, "src", "entry.ts"), "export {};\n", "utf8");
entryFile = path.join(root, "src", "entry.ts");
argv[1] = entryFile;
await fs.writeFile(entryFile, "export {};\n", "utf8");
}
it("resolves install roots from source and dist entry paths", () => {
@@ -153,26 +155,37 @@ describe("entry compile cache", () => {
});
it.each(["git", "source", "package"])(
"activates compile cache only for an enabled %s install",
"activates compiled-entry cache for an enabled %s install",
async (kind) => {
if (kind === "git") {
await fs.writeFile(path.join(root, ".git"), "gitdir: .git/worktrees/openclaw\n", "utf8");
} else if (kind === "source") {
await markSourceCheckout();
await fs.mkdir(path.join(root, "src"));
await fs.writeFile(path.join(root, "src", "entry.ts"), "export {};\n");
}
enableOpenClawCompileCache({ env: {}, installRoot: root });
expect(enableCompileCache).toHaveBeenCalledTimes(kind === "package" ? 1 : 0);
enableOpenClawCompileCache({ env: { NODE_DISABLE_COMPILE_CACHE: "1" }, installRoot: root });
enableOpenClawCompileCache({ currentFile: entryFile, env: {}, installRoot: root });
expect(enableCompileCache).toHaveBeenCalledTimes(1);
enableOpenClawCompileCache({
currentFile: entryFile,
env: { NODE_DISABLE_COMPILE_CACHE: "1" },
installRoot: root,
});
setTestEnvValue("NODE_DISABLE_COMPILE_CACHE", "1");
enableOpenClawCompileCache({ installRoot: root });
expect(enableCompileCache).toHaveBeenCalledTimes(kind === "package" ? 1 : 0);
enableOpenClawCompileCache({ currentFile: entryFile, installRoot: root });
expect(enableCompileCache).toHaveBeenCalledTimes(1);
},
);
it("leaves source entry compilation uncached", async () => {
await markSourceCheckout();
enableOpenClawCompileCache({ currentFile: entryFile, env: {}, installRoot: root });
expect(enableCompileCache).not.toHaveBeenCalled();
});
it("skips cache activation with a warning when Windows TEMP makes the path too long", () => {
vi.spyOn(os, "tmpdir").mockReturnValue(path.join(root, "x".repeat(200)));
withMockedPlatform("win32", () => {
enableOpenClawCompileCache({ env: {}, installRoot: root });
enableOpenClawCompileCache({ currentFile: entryFile, env: {}, installRoot: root });
});
expect(enableCompileCache).not.toHaveBeenCalled();
expect(writeStderr).toHaveBeenCalledExactlyOnceWith(
@@ -200,7 +213,7 @@ describe("entry compile cache", () => {
const packageJsonPath = path.join(root, "package.json");
const env = { NODE_COMPILE_CACHE: path.join(root, ".node-cache") };
await fs.writeFile(packageJsonPath, '{"version":"2026.4.29"}\n', "utf8");
enableOpenClawCompileCache({ env, installRoot: root });
enableOpenClawCompileCache({ currentFile: entryFile, env, installRoot: root });
const originalDirectory = enabledDirectory();
expect(originalDirectory).toContain(path.join(".node-cache", "openclaw"));
expect(originalDirectory).toContain("2026.4.29");
@@ -210,7 +223,7 @@ describe("entry compile cache", () => {
'{"version":"2026.4.29","installation":"replacement"}\n',
"utf8",
);
enableOpenClawCompileCache({ env, installRoot: root });
enableOpenClawCompileCache({ currentFile: entryFile, env, installRoot: root });
const replacementDirectory = enabledDirectory(1);
expect(replacementDirectory).toContain(path.join("openclaw", "2026.4.29"));
expect(replacementDirectory).not.toBe(originalDirectory);
@@ -224,7 +237,7 @@ describe("entry compile cache", () => {
deleteTestEnvValue("NODE_COMPILE_CACHE");
getCompileCacheDir.mockReturnValue(path.join(root, ".active-cache"));
}
const { completion } = await startRespawn({ currentFile: entryFile, installRoot: root });
const { completion } = await startRespawn({ currentFile: entryFile });
expect(spawn).toHaveBeenCalledOnce();
const [command, args, options] = expectDefined(spawn.mock.calls[0], "respawn call");
expect(command).toBe(process.execPath);
@@ -261,11 +274,14 @@ describe("entry compile cache", () => {
["gmail", "win32", "source", false],
["gateway", "linux", "source", false],
["status", "linux", "package", false],
["status", "linux", "compiled", false],
["status", "linux", "respawned", false],
] as const)(
"respects %s/%s respawn policy for %s",
async (command, platform, install, respawns) => {
if (install !== "package") {
if (install === "compiled") {
await fs.writeFile(path.join(root, ".git"), "gitdir: fixture\n");
} else if (install !== "package") {
await markSourceCheckout();
}
if (install === "respawned") {
@@ -278,7 +294,6 @@ describe("entry compile cache", () => {
await withMockedPlatform(platform, async () => {
const completion = respawnWithoutOpenClawCompileCacheIfNeeded({
currentFile: entryFile,
installRoot: root,
});
if (respawns) {
await spawned.promise;
@@ -293,7 +308,7 @@ describe("entry compile cache", () => {
it.each([[], ["tui"]])("keeps interactive no-cache respawns attached: %j", async (...command) => {
await markSourceCheckout();
argv = [process.execPath, entryFile, ...command];
const { completion } = await startRespawn({ currentFile: entryFile, installRoot: root });
const { completion } = await startRespawn({ currentFile: entryFile });
expect(expectDefined(spawn.mock.calls[0], "respawn call")[2]?.detached).toBe(false);
child.emit("close", 0, null);
await completion;
@@ -309,7 +324,6 @@ describe("entry compile cache", () => {
await withMockedPlatform(platform, async () => {
const { completion } = await startRespawn({
currentFile: entryFile,
installRoot: root,
});
const [, options] = expectDefined(attachChildProcessBridge.mock.calls[0], "bridge call");
expectDefined(options?.onSignal, "signal handler")("SIGTERM");
@@ -346,7 +360,6 @@ describe("entry compile cache", () => {
const prepareWriteError = vi.fn(() => writer.promise);
const diagnosticCompletion = respawnWithoutOpenClawCompileCacheIfNeeded({
currentFile: entryFile,
installRoot: root,
prepareWriteError,
});
try {
+5 -11
View File
@@ -1,6 +1,5 @@
// Manages compile-cache respawn behavior for the CLI entrypoint.
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { getCompileCacheDir } from "node:module";
import path from "node:path";
import process from "node:process";
@@ -25,11 +24,8 @@ export function resolveEntryInstallRoot(entryFile: string): string {
return entryParent === "dist" || entryParent === "src" ? path.dirname(entryDir) : entryDir;
}
function isSourceCheckoutInstallRoot(installRoot: string): boolean {
return (
existsSync(path.join(installRoot, ".git")) ||
existsSync(path.join(installRoot, "src", "entry.ts"))
);
function isSourceEntry(currentFile: string): boolean {
return path.extname(currentFile) === ".ts";
}
function isNodeCompileCacheRequested(env: NodeJS.ProcessEnv): boolean {
@@ -45,7 +41,6 @@ type OpenClawCompileCacheRespawnPlan = {
function buildOpenClawCompileCacheRespawnPlan(params: {
currentFile: string;
installRoot: string;
compileCacheDir?: string;
env?: NodeJS.ProcessEnv;
}): OpenClawCompileCacheRespawnPlan | undefined {
@@ -59,7 +54,7 @@ function buildOpenClawCompileCacheRespawnPlan(params: {
if (isForegroundGmailRunArgv(argv) || shouldKeepNativeHookRelayInProcess(argv, platform)) {
return undefined;
}
if (!isSourceCheckoutInstallRoot(params.installRoot)) {
if (!isSourceEntry(params.currentFile)) {
return undefined;
}
if (env[COMPILE_CACHE_DISABLED_RESPAWNED_ENV] === "1") {
@@ -84,13 +79,11 @@ function buildOpenClawCompileCacheRespawnPlan(params: {
export async function respawnWithoutOpenClawCompileCacheIfNeeded(params: {
currentFile: string;
installRoot: string;
env?: NodeJS.ProcessEnv;
prepareWriteError?: () => Promise<(message: string) => void | Promise<void>>;
}): Promise<boolean> {
const plan = buildOpenClawCompileCacheRespawnPlan({
currentFile: params.currentFile,
installRoot: params.installRoot,
compileCacheDir: getCompileCacheDir?.(),
env: params.env,
});
@@ -119,10 +112,11 @@ export async function respawnWithoutOpenClawCompileCacheIfNeeded(params: {
}
export function enableOpenClawCompileCache(params: {
currentFile: string;
env?: NodeJS.ProcessEnv;
installRoot: string;
}): void {
if (!isSourceCheckoutInstallRoot(params.installRoot)) {
if (!isSourceEntry(params.currentFile)) {
enableInstallCompileCache({
directory: resolveOpenClawCompileCacheDirectory(params),
env: params.env,
+1 -1
View File
@@ -166,7 +166,6 @@ async function runEntryMain(): Promise<void> {
!isNodeHostLauncherChild() &&
(await respawnWithoutOpenClawCompileCacheIfNeeded({
currentFile: entryFile,
installRoot,
env: startupEnv,
prepareWriteError: async () => {
// The child environment was already snapshotted. Load dotenv only to format
@@ -177,6 +176,7 @@ async function runEntryMain(): Promise<void> {
}));
if (!waitingForCompileCacheRespawn) {
enableOpenClawCompileCache({
currentFile: entryFile,
installRoot,
});
@@ -15,6 +15,7 @@ fs.writeFileSync(path.join(installRoot, "package.json"), '{"version":"2026.9.6"}
assert.equal(getCompileCacheDir(), undefined);
const beforeEnable = { ...process.env };
enableOpenClawCompileCache({
currentFile: path.join(installRoot, "dist", "entry.js"),
installRoot,
env: { ...process.env, NODE_COMPILE_CACHE: path.join(root, "native-cache") },
});
@@ -36,9 +36,10 @@ fs.mkdirSync(installRoot);
fs.writeFileSync(path.join(installRoot, "package.json"), '{"version":"2026.9.6"}');
assert.equal(getCompileCacheDir(), undefined, "fixture must start without a native cache");
const initialEnv = { ...process.env };
if (testCase.owner === "source") {
fs.writeFileSync(path.join(installRoot, ".git"), "gitdir: fixture");
}
const currentFile = path.join(
installRoot,
testCase.owner === "source" ? "src/entry.ts" : "dist/entry.js",
);
if (testCase.owner === "foreign") {
// Negative control: a direct Node enable is NOT OpenClaw ownership.
const enabled = enableCompileCache(path.join(root, "foreign"));
@@ -47,10 +48,11 @@ if (testCase.owner === "foreign") {
if (testCase.owner === "failed") {
const blocked = path.join(root, "not-a-directory");
fs.writeFileSync(blocked, "fixture");
enableOpenClawCompileCache({ installRoot, env: { NODE_COMPILE_CACHE: blocked } });
enableOpenClawCompileCache({ currentFile, installRoot, env: { NODE_COMPILE_CACHE: blocked } });
} else {
// Positive control goes through the real OpenClaw entry enable owner.
enableOpenClawCompileCache({
currentFile,
installRoot,
env: { ...process.env, NODE_COMPILE_CACHE: path.join(root, "native-cache") },
});
@@ -72,7 +74,10 @@ if (owned) {
// A later enable attempt must not replace the first owner's input.
const otherRoot = path.join(root, "other-install");
fs.mkdirSync(otherRoot);
enableOpenClawCompileCache({ installRoot: otherRoot });
enableOpenClawCompileCache({
currentFile: path.join(otherRoot, "dist", "entry.js"),
installRoot: otherRoot,
});
assert.equal(resolveNodeCompileCacheEnv({}).NODE_COMPILE_CACHE, handoff.NODE_COMPILE_CACHE);
assert.equal(getCompileCacheDir(), parentDirectory);
} else {
+1 -1
View File
@@ -1851,7 +1851,7 @@ console.log(JSON.stringify({ parent: process.pid, bun: process.versions.bun, mar
import { enableOpenClawCompileCache } from "./cache-owner.mjs";
const before = { ...process.env };
// First enable for direct entry; ALREADY_ENABLED after the real launcher.
enableOpenClawCompileCache({ installRoot: ${JSON.stringify(fixtureRoot)} });
enableOpenClawCompileCache({ currentFile: ${JSON.stringify(path.join(fixtureRoot, mode === "source" ? "src/entry.ts" : "dist/entry.js"))}, installRoot: ${JSON.stringify(fixtureRoot)} });
const parentDirectory = getCompileCacheDir() ?? null;
const a = resolveA();
const b = resolveB();