Skip to content
Merged
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
43 changes: 41 additions & 2 deletions packages/evals/src/cli/runTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ import { exercisesPath } from "../exercises/index.js"

import { getTag, isDockerContainer } from "./utils.js"

class SubprocessTimeoutError extends Error {
constructor(timeout: number) {
super(`Subprocess timeout after ${timeout}ms`)
this.name = "SubprocessTimeoutError"
}
}

type RunTaskOptions = {
run: Run
task: Task
Expand Down Expand Up @@ -196,7 +203,9 @@ export const runTask = async ({ run, task, publish }: RunTaskOptions) => {
await updateTask(task.id, { finishedAt: new Date() })
}

if (!isClientDisconnected) {
if (isClientDisconnected) {
logError("client disconnected before task finished")
} else {
if (rooTaskId) {
log("closing task")
client.sendCommand({ commandName: TaskCommandName.CloseTask, data: rooTaskId })
Expand All @@ -206,6 +215,36 @@ export const runTask = async ({ run, task, publish }: RunTaskOptions) => {
client.disconnect()
}

log("waiting for subprocess to finish")
controller.abort()
await subprocess

// Wait for subprocess to finish gracefully, with a timeout.
const SUBPROCESS_TIMEOUT = 10_000

try {
await Promise.race([
subprocess,
new Promise((_, reject) =>
setTimeout(() => reject(new SubprocessTimeoutError(SUBPROCESS_TIMEOUT)), SUBPROCESS_TIMEOUT),
),
])

log("subprocess finished gracefully")
} catch (error) {
if (error instanceof SubprocessTimeoutError) {
logError("subprocess did not finish within timeout, force killing")

try {
if (subprocess.kill("SIGKILL")) {
log("SIGKILL sent to subprocess")
} else {
logError("failed to send SIGKILL to subprocess")
}
} catch (killError) {
logError("subprocess.kill(SIGKILL) failed:", killError)
}
} else {
throw error
}
}
}
Loading