feat(desktop): surface local server startup failures (#30822)

This commit is contained in:
Luke Parker 2026-06-05 08:45:48 +10:00 committed by GitHub
commit b1a7ee5695
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 175 additions and 5 deletions

View file

@ -0,0 +1,37 @@
import { describe, expect, test } from "bun:test"
import { Cause, Deferred, Effect, Exit, Fiber } from "effect"
import { forwardInitializationFailure } from "./initialization"
describe("desktop initialization", () => {
const failure = new Error("sidecar startup failed")
const expectFailure = (exit: Exit.Exit<unknown, unknown>) => {
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isSuccess(exit)) return
expect(Cause.squash(exit.cause)).toBe(failure)
}
test("forwards loading task failures before renderer initialization", () => {
const exit = Effect.runSync(
Effect.gen(function* () {
const initialization = yield* Deferred.make<never, unknown>()
yield* forwardInitializationFailure(initialization)(Effect.die(failure)).pipe(Effect.exit)
return yield* Deferred.await(initialization).pipe(Effect.exit)
}),
)
expectFailure(exit)
})
test("forwards loading task failures while renderer initialization waits", () => {
const exit = Effect.runSync(
Effect.gen(function* () {
const initialization = yield* Deferred.make<never, unknown>()
const waiting = yield* Deferred.await(initialization).pipe(Effect.exit, Effect.forkChild)
yield* forwardInitializationFailure(initialization)(Effect.die(failure)).pipe(Effect.exit)
return yield* Fiber.join(waiting)
}),
)
expectFailure(exit)
})
})

View file

@ -14,6 +14,7 @@ import type { ServerReadyData, WslConfig } from "../preload/types"
import { checkAppExists, resolveAppPath, wslPath } from "./apps"
import { CHANNEL, UPDATER_ENABLED } from "./constants"
import { registerIpcHandlers, sendDeepLinks, sendMenuCommand } from "./ipc"
import { forwardInitializationFailure } from "./initialization"
import { exportDebugLogs, initCrashReporter, initLogging, startNetLog, write as writeLog } from "./logging"
import { parseMarkdown } from "./markdown"
import { createMenu } from "./menu"
@ -207,7 +208,7 @@ const main = Effect.gen(function* () {
})
}
const serverReady = Deferred.makeUnsafe<ServerReadyData>()
const serverReady = Deferred.makeUnsafe<ServerReadyData, unknown>()
registerIpcHandlers({
killSidecar: () => killSidecar(),
@ -314,7 +315,7 @@ const main = Effect.gen(function* () {
)
logger.log("loading task finished")
}).pipe(Effect.forkChild)
}).pipe(forwardInitializationFailure(serverReady), Effect.forkChild)
yield* Fiber.await(loadingTask)

View file

@ -0,0 +1,6 @@
import { Deferred, Effect } from "effect"
export function forwardInitializationFailure<A>(initialization: Deferred.Deferred<A, unknown>) {
return <B, E, R>(effect: Effect.Effect<B, E, R>) =>
effect.pipe(Effect.tapCause((cause) => Deferred.failCause(initialization, cause)))
}