fix: stream bash output and harden OpenCode connectivity (#2522)
* fix(ui): stream bash tool output while running * perf(ui): render streaming bash output incrementally * fix(ui): keep tool duration timer running * fix(web): recover stalled OpenCode SSE streams * fix(web): prevent OpenCode restart storms * fix: address streaming recovery review
This commit is contained in:
committed by
GitHub
parent
c84305bf7e
commit
0f830f8804
@@ -40,6 +40,7 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
||||
getManagedOpenCodeShellEnvSnapshot,
|
||||
getManagedOpenCodeEnv = async () => ({}),
|
||||
getActiveSessionCount = () => 0,
|
||||
now = Date.now,
|
||||
} = deps;
|
||||
|
||||
const killProcessOnPort = (port) => {
|
||||
@@ -871,18 +872,21 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
||||
const STALE_BUSY_GRACE_MS = 2 * 60 * 1000;
|
||||
let lastUnhealthyWithBusySessionsAt = 0;
|
||||
let consecutiveHealthFailures = 0;
|
||||
let lastCountedHealthFailureAt = 0;
|
||||
let healthProbePromise = null;
|
||||
let healthCheckCyclePromise = null;
|
||||
let lastHealthProbeResult = null;
|
||||
let healthFailureCountIntervalMs = 15_000;
|
||||
|
||||
const resetHealthFailureState = () => {
|
||||
consecutiveHealthFailures = 0;
|
||||
lastUnhealthyWithBusySessionsAt = 0;
|
||||
lastCountedHealthFailureAt = 0;
|
||||
};
|
||||
|
||||
const probeOpenCodeHealth = async () => {
|
||||
const now = Date.now();
|
||||
if (lastHealthProbeResult && now - lastHealthProbeResult.at < HEALTH_CHECK_RESULT_CACHE_MS) {
|
||||
const checkedAt = now();
|
||||
if (lastHealthProbeResult && checkedAt - lastHealthProbeResult.at < HEALTH_CHECK_RESULT_CACHE_MS) {
|
||||
return lastHealthProbeResult.healthy;
|
||||
}
|
||||
|
||||
@@ -892,7 +896,7 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
||||
|
||||
healthProbePromise = isOpenCodeProcessHealthy()
|
||||
.then((healthy) => {
|
||||
lastHealthProbeResult = { at: Date.now(), healthy };
|
||||
lastHealthProbeResult = { at: now(), healthy };
|
||||
return healthy;
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -909,13 +913,13 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const checkedAt = now();
|
||||
if (!lastUnhealthyWithBusySessionsAt) {
|
||||
lastUnhealthyWithBusySessionsAt = now;
|
||||
lastUnhealthyWithBusySessionsAt = checkedAt;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (now - lastUnhealthyWithBusySessionsAt >= STALE_BUSY_GRACE_MS) {
|
||||
if (checkedAt - lastUnhealthyWithBusySessionsAt >= STALE_BUSY_GRACE_MS) {
|
||||
console.warn(
|
||||
`[lifecycle] OpenCode unhealthy with ${activeCount} busy session(s) for > 2 min — forcing restart`
|
||||
);
|
||||
@@ -940,6 +944,11 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
||||
await restartOpenCode();
|
||||
return;
|
||||
}
|
||||
const checkedAt = now();
|
||||
if (lastCountedHealthFailureAt && checkedAt - lastCountedHealthFailureAt < healthFailureCountIntervalMs) {
|
||||
return;
|
||||
}
|
||||
lastCountedHealthFailureAt = checkedAt;
|
||||
consecutiveHealthFailures += 1;
|
||||
console.warn(
|
||||
`[lifecycle] ${source} health check failed (${consecutiveHealthFailures}/${HEALTH_CHECK_MAX_CONSECUTIVE_FAILURES})`
|
||||
@@ -974,6 +983,7 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
||||
}
|
||||
|
||||
const effectiveIntervalMs = HEALTH_CHECK_INTERVAL_OVERRIDE_MS || healthCheckIntervalMs;
|
||||
healthFailureCountIntervalMs = effectiveIntervalMs;
|
||||
|
||||
state.healthCheckInterval = setInterval(async () => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user