chore: test deploy snapshot
This commit is contained in:
@@ -58,6 +58,48 @@ const CODEX_LIVE_FINISHED_RETENTION_MS = Math.max(
|
||||
);
|
||||
const activeCodexExecutions = new Map();
|
||||
const recentCodexExecutions = new Map();
|
||||
let runnerShutdownSignal = null;
|
||||
|
||||
function logRunner(message) {
|
||||
process.stdout.write("[server-command-runner] " + new Date().toISOString() + " " + message + "\n");
|
||||
}
|
||||
|
||||
function summarizeActiveExecutionIds(limit = 8) {
|
||||
const requestIds = Array.from(activeCodexExecutions.keys()).slice(0, limit);
|
||||
const suffix = activeCodexExecutions.size > requestIds.length ? " +" + (activeCodexExecutions.size - requestIds.length) + " more" : "";
|
||||
return requestIds.length > 0 ? requestIds.join(", ") + suffix : "none";
|
||||
}
|
||||
|
||||
function resolveSignalExitCode(signal) {
|
||||
switch (signal) {
|
||||
case "SIGINT":
|
||||
return 130;
|
||||
case "SIGHUP":
|
||||
return 129;
|
||||
case "SIGTERM":
|
||||
return 143;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function shutdownRunnerFromSignal(signal) {
|
||||
if (runnerShutdownSignal) {
|
||||
return;
|
||||
}
|
||||
|
||||
runnerShutdownSignal = signal;
|
||||
logRunner("received " + signal + "; activeExecutions=" + activeCodexExecutions.size + "; requestIds=" + summarizeActiveExecutionIds());
|
||||
process.exit(resolveSignalExitCode(signal));
|
||||
}
|
||||
|
||||
process.once("SIGTERM", () => shutdownRunnerFromSignal("SIGTERM"));
|
||||
process.once("SIGINT", () => shutdownRunnerFromSignal("SIGINT"));
|
||||
process.once("SIGHUP", () => shutdownRunnerFromSignal("SIGHUP"));
|
||||
process.on("exit", (code) => {
|
||||
const shutdownLabel = runnerShutdownSignal === null ? "none" : runnerShutdownSignal;
|
||||
logRunner("exiting with code " + code + "; shutdownSignal=" + shutdownLabel + "; activeExecutions=" + activeCodexExecutions.size);
|
||||
});
|
||||
|
||||
function resolveCodexLiveModel(value) {
|
||||
const normalized = String(value ?? '').trim();
|
||||
@@ -798,6 +840,7 @@ async function runCodexLiveExecution(payload, response) {
|
||||
child,
|
||||
tempDir,
|
||||
});
|
||||
logRunner("spawned Codex child pid=" + (child.pid ?? "unknown") + " requestId=" + requestId + " sessionId=" + sessionId + " model=" + codexModel + " idleTimeoutMs=" + configuredIdleTimeoutMs + " maxExecutionMs=" + configuredMaxExecutionMs);
|
||||
activeCodexExecutions.set(requestId, executionRecord);
|
||||
attachCodexExecutionSubscriber(executionRecord, response);
|
||||
broadcastCodexExecutionEvent(executionRecord, {
|
||||
@@ -820,7 +863,7 @@ async function runCodexLiveExecution(payload, response) {
|
||||
}
|
||||
};
|
||||
|
||||
const requestTermination = (message) => {
|
||||
const requestTermination = (message, reason = 'runner-termination') => {
|
||||
if (terminationRequested) {
|
||||
return;
|
||||
}
|
||||
@@ -833,6 +876,7 @@ async function runCodexLiveExecution(payload, response) {
|
||||
message,
|
||||
});
|
||||
|
||||
logRunner("terminating Codex child pid=" + (child.pid ?? "unknown") + " requestId=" + requestId + " reason=" + reason + " message=" + message);
|
||||
child.kill('SIGTERM');
|
||||
setTimeout(() => {
|
||||
if (!child.killed) {
|
||||
@@ -853,6 +897,7 @@ async function runCodexLiveExecution(payload, response) {
|
||||
idleTimer = setTimeout(() => {
|
||||
requestTermination(
|
||||
`Codex Live 실행이 ${Math.round(configuredIdleTimeoutMs / 1000)}초 동안 출력이 없어 중단되었습니다.`,
|
||||
'idle-timeout',
|
||||
);
|
||||
}, configuredIdleTimeoutMs);
|
||||
idleTimer.unref?.();
|
||||
@@ -861,6 +906,7 @@ async function runCodexLiveExecution(payload, response) {
|
||||
executionTimer = setTimeout(() => {
|
||||
requestTermination(
|
||||
`Codex Live 실행이 ${Math.round(configuredMaxExecutionMs / 1000)}초를 넘어 중단되었습니다.`,
|
||||
'max-execution-timeout',
|
||||
);
|
||||
}, configuredMaxExecutionMs);
|
||||
executionTimer.unref?.();
|
||||
@@ -968,6 +1014,7 @@ async function runCodexLiveExecution(payload, response) {
|
||||
|
||||
child.on('error', async (error) => {
|
||||
clearExecutionTimers();
|
||||
logRunner("Codex child process error requestId=" + requestId + " pid=" + (child.pid ?? "unknown") + " message=" + (error instanceof Error ? error.message : String(error)));
|
||||
broadcastCodexExecutionEvent(executionRecord, {
|
||||
type: 'error',
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
@@ -979,8 +1026,9 @@ async function runCodexLiveExecution(payload, response) {
|
||||
finalizeCodexExecution(executionRecord);
|
||||
});
|
||||
|
||||
child.on('close', async (code) => {
|
||||
child.on('close', async (code, signal) => {
|
||||
clearExecutionTimers();
|
||||
logRunner("Codex child closed requestId=" + requestId + " pid=" + (child.pid ?? "unknown") + " exitCode=" + (code ?? "null") + " signal=" + (signal ?? "none") + " terminationRequested=" + terminationRequested);
|
||||
const trailingLine = jsonLineBuffer.trim();
|
||||
if (trailingLine) {
|
||||
handleCodexJsonLine(trailingLine);
|
||||
@@ -1204,6 +1252,7 @@ const server = createServer(async (request, response) => {
|
||||
}
|
||||
|
||||
try {
|
||||
logRunner("received cancel request for requestId=" + requestId + "; forwarding SIGTERM to child pid=" + (activeExecution.child.pid ?? "unknown"));
|
||||
activeExecution.child.kill('SIGTERM');
|
||||
setTimeout(() => {
|
||||
const current = activeCodexExecutions.get(requestId);
|
||||
@@ -1239,5 +1288,5 @@ server.listen(port, host, () => {
|
||||
});
|
||||
}, 10_000);
|
||||
heartbeatTimer.unref();
|
||||
process.stdout.write(`server-command-runner listening on http://${host}:${port}\n`);
|
||||
logRunner("listening on http://" + host + ":" + port + "; pid=" + process.pid + "; ppid=" + process.ppid + "; startedAt=" + startedAt + "; logFile=" + runnerLogFile);
|
||||
});
|
||||
|
||||
0
scripts/server-command-runner-supervisor.sh
Normal file → Executable file
0
scripts/server-command-runner-supervisor.sh
Normal file → Executable file
Reference in New Issue
Block a user