fix(background-agent): bound session abort waits
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { log } from "../../shared"
|
||||
import type { OpencodeClient } from "./opencode-client"
|
||||
|
||||
export async function abortWithTimeout(
|
||||
client: OpencodeClient,
|
||||
sessionID: string,
|
||||
timeoutMs = 10_000,
|
||||
): Promise<boolean> {
|
||||
let timeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
try {
|
||||
const result = await Promise.race([
|
||||
client.session.abort({ path: { id: sessionID } }).then(() => "aborted" as const),
|
||||
new Promise<"timed_out">((resolve) => {
|
||||
timeoutHandle = setTimeout(() => {
|
||||
resolve("timed_out")
|
||||
}, timeoutMs)
|
||||
}),
|
||||
])
|
||||
|
||||
if (result === "timed_out") {
|
||||
log("[background-agent] Session abort timed out; continuing cleanup:", {
|
||||
sessionID,
|
||||
timeoutMs,
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} finally {
|
||||
if (timeoutHandle) {
|
||||
clearTimeout(timeoutHandle)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
selectFallbackProvider,
|
||||
} from "../../shared/model-error-classifier"
|
||||
import { transformModelForProvider } from "../../shared/provider-model-id-transform"
|
||||
import { abortWithTimeout } from "./abort-with-timeout"
|
||||
|
||||
export async function tryFallbackRetry(args: {
|
||||
task: BackgroundTask
|
||||
@@ -123,7 +124,7 @@ export async function tryFallbackRetry(args: {
|
||||
}
|
||||
|
||||
if (previousSessionID) {
|
||||
await client.session.abort({ path: { id: previousSessionID } }).catch(() => {})
|
||||
await abortWithTimeout(client, previousSessionID).catch(() => {})
|
||||
}
|
||||
|
||||
queue.push({ task, input: retryInput })
|
||||
|
||||
@@ -238,7 +238,7 @@ function stubNotifyParentSession(manager: BackgroundManager): void {
|
||||
}
|
||||
|
||||
async function flushBackgroundNotifications(): Promise<void> {
|
||||
for (let i = 0; i < 6; i++) {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
await Promise.resolve()
|
||||
}
|
||||
}
|
||||
@@ -2570,7 +2570,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => {
|
||||
abortCalled,
|
||||
new Promise<never>((_, reject) => setTimeout(() => reject(new Error("timeout")), 100)),
|
||||
])
|
||||
await Promise.resolve()
|
||||
await flushBackgroundNotifications()
|
||||
|
||||
// then
|
||||
const updatedTask = manager.getTask(task.id)
|
||||
|
||||
@@ -57,6 +57,7 @@ import { join } from "node:path"
|
||||
import { pruneStaleTasksAndNotifications } from "./task-poller"
|
||||
import { checkAndInterruptStaleTasks } from "./task-poller"
|
||||
import { removeTaskToastTracking } from "./remove-task-toast-tracking"
|
||||
import { abortWithTimeout } from "./abort-with-timeout"
|
||||
import {
|
||||
MIN_SESSION_GONE_POLLS,
|
||||
verifySessionExists as verifySessionStillExists,
|
||||
@@ -193,9 +194,7 @@ export class BackgroundManager {
|
||||
|
||||
private async abortSessionWithLogging(sessionID: string, reason: string): Promise<void> {
|
||||
try {
|
||||
await this.client.session.abort({
|
||||
path: { id: sessionID },
|
||||
})
|
||||
await abortWithTimeout(this.client, sessionID)
|
||||
} catch (error) {
|
||||
log(`[background-agent] Failed to abort session during ${reason}:`, {
|
||||
sessionID,
|
||||
@@ -1985,9 +1984,7 @@ export class BackgroundManager {
|
||||
if (task.status === "running" && task.sessionID) {
|
||||
abortRequests.push({
|
||||
sessionID: task.sessionID,
|
||||
promise: this.client.session.abort({
|
||||
path: { id: task.sessionID },
|
||||
}),
|
||||
promise: abortWithTimeout(this.client, task.sessionID),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
TERMINAL_TASK_TTL_MS,
|
||||
TASK_TTL_MS,
|
||||
} from "./constants"
|
||||
import { abortWithTimeout } from "./abort-with-timeout"
|
||||
import { removeTaskToastTracking } from "./remove-task-toast-tracking"
|
||||
import { MIN_SESSION_GONE_POLLS, verifySessionExists } from "./session-existence"
|
||||
|
||||
@@ -167,7 +168,7 @@ export async function checkAndInterruptStaleTasks(args: {
|
||||
|
||||
onTaskInterrupted(task)
|
||||
|
||||
abortPromises.push(client.session.abort({ path: { id: sessionID } }))
|
||||
abortPromises.push(abortWithTimeout(client, sessionID))
|
||||
log(`[background-agent] Task ${task.id} interrupted: no progress since start`)
|
||||
|
||||
try {
|
||||
@@ -205,7 +206,7 @@ export async function checkAndInterruptStaleTasks(args: {
|
||||
|
||||
onTaskInterrupted(task)
|
||||
|
||||
abortPromises.push(client.session.abort({ path: { id: sessionID } }))
|
||||
abortPromises.push(abortWithTimeout(client, sessionID))
|
||||
log(`[background-agent] Task ${task.id} interrupted: stale timeout`)
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user