mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 00:25:34 +08:00
Speed up compiler startup and trim release runtime packs
- Cache host libc detection and load TypeScript 5 only when needed. - Exclude debug payloads from release runtime packs and vendor archives. - Preserve native self-hosting, portable diagnostics, and reliable Sandbox execution.
This commit is contained in:
@@ -8,9 +8,13 @@ export const shellQuote = (value) => `'${value.replaceAll("'", `'"'"'`)}'`;
|
||||
* same script records the remote exit status for either transport. */
|
||||
export function sandboxCommand(command, args, exitMarker) {
|
||||
const statusPath = `/tmp/${exitMarker}.status`;
|
||||
const logPath = `/tmp/${exitMarker}.log`;
|
||||
const pendingStatus = statusPath + ".pending";
|
||||
const script =
|
||||
`${[command, ...args].map(shellQuote).join(" ")}; scriptc_status=$?; ` +
|
||||
`printf '%s\\n' "$scriptc_status" > ${shellQuote(statusPath)}; ` +
|
||||
`( ${[command, ...args].map(shellQuote).join(" ")}; scriptc_status=$?; ` +
|
||||
`printf '%s\\n' "$scriptc_status" > ${shellQuote(pendingStatus)} ) 2>&1 | tee ${shellQuote(logPath)}; ` +
|
||||
`mv ${shellQuote(pendingStatus)} ${shellQuote(statusPath)}; ` +
|
||||
`scriptc_status=$(cat ${shellQuote(statusPath)}); ` +
|
||||
`printf '\\n${exitMarker}%s\\n' "$scriptc_status"`;
|
||||
const scriptPath = `/tmp/${exitMarker}.sh`;
|
||||
const file = Buffer.byteLength(script, "utf8") > MAX_INLINE_SANDBOX_COMMAND_BYTES;
|
||||
@@ -18,6 +22,7 @@ export function sandboxCommand(command, args, exitMarker) {
|
||||
script,
|
||||
scriptPath,
|
||||
statusPath,
|
||||
logPath,
|
||||
file,
|
||||
argv: file ? ["sh", scriptPath] : ["sh", "-c", script],
|
||||
};
|
||||
|
||||
@@ -21,12 +21,20 @@ function loadLocalEnv() {
|
||||
export function sandboxRunnerConfig(env) {
|
||||
loadLocalEnv();
|
||||
const source = env ?? process.env;
|
||||
const sandboxTimeout = source.SCRIPTC_SANDBOX_TIMEOUT ?? "45m";
|
||||
const duration = /^(\d+)\s*(ms|s|m|h)$/.exec(sandboxTimeout.trim());
|
||||
const units = { ms: 1, s: 1000, m: 60_000, h: 3_600_000 };
|
||||
const sandboxTimeoutMs = duration ? Number(duration[1]) * units[duration[2]] : 0;
|
||||
if (!Number.isSafeInteger(sandboxTimeoutMs) || sandboxTimeoutMs <= 0 || sandboxTimeoutMs > 2_147_483_647) {
|
||||
throw new Error("SCRIPTC_SANDBOX_TIMEOUT must be a positive duration such as 45m or 2h");
|
||||
}
|
||||
return {
|
||||
vcpus: source.SCRIPTC_SANDBOX_VCPUS ?? "8",
|
||||
testWorkers: source.SCRIPTC_TEST_WORKERS ?? "4",
|
||||
localTestWorkers: source.SCRIPTC_LOCAL_TEST_WORKERS ?? "2",
|
||||
localCaseShards: source.SCRIPTC_LOCAL_CASE_SHARDS ?? "2",
|
||||
sandboxTimeout: source.SCRIPTC_SANDBOX_TIMEOUT ?? "45m",
|
||||
sandboxTimeout,
|
||||
sandboxTimeoutMs,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ const {
|
||||
localTestWorkers,
|
||||
localCaseShards,
|
||||
sandboxTimeout,
|
||||
sandboxTimeoutMs,
|
||||
} = sandboxRunnerConfig();
|
||||
|
||||
if (!["plain", "san", "both"].includes(values.lane)) {
|
||||
@@ -382,14 +383,14 @@ const execIn = async (
|
||||
args,
|
||||
env = {},
|
||||
task = "",
|
||||
wallTimeoutMs = 15 * 60_000,
|
||||
wallTimeoutMs = sandboxTimeoutMs,
|
||||
workdir = "/workspace",
|
||||
idleTimeoutMs = 90_000,
|
||||
) => {
|
||||
const envArgs = Object.entries(env).flatMap(([key, value]) => ["--env", `${key}=${value}`]);
|
||||
const exitMarker = `__SCRIPTC_REMOTE_EXIT_${randomBytes(12).toString("hex")}__`;
|
||||
const prepared = sandboxCommand(command, args, exitMarker);
|
||||
const { statusPath } = prepared;
|
||||
const { statusPath, logPath } = prepared;
|
||||
const label = task ? `${worker.label} ${task}` : worker.label;
|
||||
if (prepared.file) {
|
||||
const localScript = join(temp, `${exitMarker}.sh`);
|
||||
@@ -416,6 +417,11 @@ const execIn = async (
|
||||
...prepared.argv,
|
||||
];
|
||||
const deadline = Date.now() + wallTimeoutMs;
|
||||
const recoveredLog = async () => {
|
||||
await vercel(["sandbox", "exec", "--timeout", "1m", "--workdir", workdir, worker.name, "tail", "-n", "160", logPath], {
|
||||
label: `${label} recovered log`, timeoutMs: 60_000, idleTimeoutMs: 30_000,
|
||||
}).catch((error) => console.warn(`[${label}] could not recover ${logPath}: ${error.message}`));
|
||||
};
|
||||
try {
|
||||
await vercel(commandArgs, {
|
||||
exitMarker,
|
||||
@@ -428,7 +434,10 @@ const execIn = async (
|
||||
console.warn(`[${label}] CLI completion was not confirmed (${error.message}); checking the remote command status...`);
|
||||
for (;;) {
|
||||
const remaining = deadline - Date.now();
|
||||
if (remaining <= 0) throw new Error(`${label} did not confirm completion before its timeout`, { cause: error });
|
||||
if (remaining <= 0) {
|
||||
await recoveredLog();
|
||||
throw new Error(`${label} did not confirm completion before its timeout`, { cause: error });
|
||||
}
|
||||
const probeMarker = `__SCRIPTC_REMOTE_PROBE_${randomBytes(12).toString("hex")}__`;
|
||||
const probeScript = sandboxStatusCommand(statusPath, probeMarker, Math.min(20, Math.floor(remaining / 1000)));
|
||||
try {
|
||||
@@ -441,9 +450,13 @@ const execIn = async (
|
||||
timeoutMs: Math.min(60_000, remaining),
|
||||
},
|
||||
);
|
||||
await recoveredLog();
|
||||
return;
|
||||
} catch (probeError) {
|
||||
if (probeError.remoteExitCode !== REMOTE_COMMAND_PENDING) throw probeError;
|
||||
if (probeError.remoteExitCode !== REMOTE_COMMAND_PENDING) {
|
||||
await recoveredLog();
|
||||
throw probeError;
|
||||
}
|
||||
console.log(`[${label}] remote command has not recorded completion; waiting...`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user