fix(#2855): tmux health check fails across module instances in same process
The server-health module used module-level state for inProcessServerRunning, which doesn't survive when Bun loads separate module instances in the same process. Fix: use globalThis with Symbol.for key so the flag is truly process-global. - server-health.ts: replace module-level boolean with globalThis[Symbol.for()] - export markServerRunningInProcess from tmux-utils barrel - test: verify flag skips HTTP fetch, verify globalThis persistence
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
|||||||
isInsideTmux,
|
isInsideTmux,
|
||||||
isServerRunning,
|
isServerRunning,
|
||||||
resetServerCheck,
|
resetServerCheck,
|
||||||
|
markServerRunningInProcess,
|
||||||
spawnTmuxPane,
|
spawnTmuxPane,
|
||||||
closeTmuxPane,
|
closeTmuxPane,
|
||||||
applyLayout,
|
applyLayout,
|
||||||
@@ -165,6 +166,46 @@ describe("resetServerCheck", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("markServerRunningInProcess", () => {
|
||||||
|
const originalFetch = globalThis.fetch
|
||||||
|
const SERVER_RUNNING_KEY = Symbol.for("oh-my-opencode:server-running-in-process")
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
resetServerCheck()
|
||||||
|
delete (globalThis as Record<symbol, boolean>)[SERVER_RUNNING_KEY]
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
globalThis.fetch = originalFetch
|
||||||
|
delete (globalThis as Record<symbol, boolean>)[SERVER_RUNNING_KEY]
|
||||||
|
})
|
||||||
|
|
||||||
|
test("skips HTTP fetch when marked as running in-process", async () => {
|
||||||
|
// given
|
||||||
|
const fetchMock = mock(async () => ({ ok: true })) as any
|
||||||
|
globalThis.fetch = fetchMock
|
||||||
|
markServerRunningInProcess()
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = await isServerRunning("http://localhost:4096")
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toBe(true)
|
||||||
|
expect(fetchMock.mock.calls.length).toBe(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses globalThis so flag survives across module instances", () => {
|
||||||
|
// given
|
||||||
|
markServerRunningInProcess()
|
||||||
|
|
||||||
|
// when
|
||||||
|
const flag = (globalThis as Record<symbol, boolean>)[SERVER_RUNNING_KEY]
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(flag).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("tmux pane functions", () => {
|
describe("tmux pane functions", () => {
|
||||||
test("spawnTmuxPane is exported as function", async () => {
|
test("spawnTmuxPane is exported as function", async () => {
|
||||||
// given, #when
|
// given, #when
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export { isInsideTmux, getCurrentPaneId } from "./tmux-utils/environment"
|
export { isInsideTmux, getCurrentPaneId } from "./tmux-utils/environment"
|
||||||
export type { SplitDirection } from "./tmux-utils/environment"
|
export type { SplitDirection } from "./tmux-utils/environment"
|
||||||
|
|
||||||
export { isServerRunning, resetServerCheck } from "./tmux-utils/server-health"
|
export { isServerRunning, resetServerCheck, markServerRunningInProcess } from "./tmux-utils/server-health"
|
||||||
|
|
||||||
export { getPaneDimensions } from "./tmux-utils/pane-dimensions"
|
export { getPaneDimensions } from "./tmux-utils/pane-dimensions"
|
||||||
export type { PaneDimensions } from "./tmux-utils/pane-dimensions"
|
export type { PaneDimensions } from "./tmux-utils/pane-dimensions"
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
let serverAvailable: boolean | null = null
|
let serverAvailable: boolean | null = null
|
||||||
let serverCheckUrl: string | null = null
|
let serverCheckUrl: string | null = null
|
||||||
let inProcessServerRunning = false
|
|
||||||
|
const SERVER_RUNNING_KEY = Symbol.for("oh-my-opencode:server-running-in-process")
|
||||||
|
|
||||||
function delay(milliseconds: number): Promise<void> {
|
function delay(milliseconds: number): Promise<void> {
|
||||||
return new Promise((resolve) => setTimeout(resolve, milliseconds))
|
return new Promise((resolve) => setTimeout(resolve, milliseconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function markServerRunningInProcess(): void {
|
export function markServerRunningInProcess(): void {
|
||||||
inProcessServerRunning = true
|
;(globalThis as Record<symbol, boolean>)[SERVER_RUNNING_KEY] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMarkedRunningInProcess(): boolean {
|
||||||
|
return (globalThis as Record<symbol, boolean>)[SERVER_RUNNING_KEY] === true
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isServerRunning(serverUrl: string): Promise<boolean> {
|
export async function isServerRunning(serverUrl: string): Promise<boolean> {
|
||||||
if (inProcessServerRunning) {
|
if (isMarkedRunningInProcess()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user