fix(core): hide recovered wake failures

This commit is contained in:
Kit Langton 2026-06-06 08:13:08 -04:00
commit ecf6c532d5
2 changed files with 19 additions and 18 deletions

View file

@ -39,14 +39,14 @@ export interface Coordinator<Key, A, E> {
/** One Session's process-local execution lane: one active demand and at most one coalesced follow-up. */
type Entry<A, E> = {
readonly done: Deferred.Deferred<A, E>
readonly settled: Deferred.Deferred<Exit.Exit<A, E>>
readonly settled: Deferred.Deferred<Exit.Exit<A, E> | undefined>
current: Demand
pending?: Demand
explicitWaiter?: Deferred.Deferred<A, E>
interruptSeq?: number
owner?: Fiber.Fiber<void, never>
stopping: boolean
advisoryRetriesRemaining: number
advisoryRetryAvailable: boolean
}
/** Combines follow-up demand: runs dominate, while wakes retain the newest durable admission sequence. */
@ -82,17 +82,16 @@ export const make = <Key, A, E>(options: {
}),
)
const makeEntry = (
current: Demand,
explicitWaiter?: Deferred.Deferred<A, E>,
advisoryRetriesRemaining = current._tag === "wake" ? 1 : 0,
): Entry<A, E> => ({
const makeEntry = (current: Demand, options?: {
readonly explicitWaiter?: Deferred.Deferred<A, E>
readonly advisoryRetryAvailable?: boolean
}): Entry<A, E> => ({
done: Deferred.makeUnsafe<A, E>(),
settled: Deferred.makeUnsafe<Exit.Exit<A, E>>(),
settled: Deferred.makeUnsafe<Exit.Exit<A, E> | undefined>(),
current,
explicitWaiter,
explicitWaiter: options?.explicitWaiter,
stopping: false,
advisoryRetriesRemaining,
advisoryRetryAvailable: options?.advisoryRetryAvailable ?? current._tag === "wake",
})
const start = (key: Key, entry: Entry<A, E>, demand: Demand, successor = false) => {
@ -138,7 +137,7 @@ export const make = <Key, A, E>(options: {
const pending = entry.pending
entry.pending = undefined
entry.current = pending
entry.advisoryRetriesRemaining = pending._tag === "wake" ? 1 : 0
entry.advisoryRetryAvailable = pending._tag === "wake"
start(key, entry, pending, true)
return
}
@ -150,15 +149,16 @@ export const make = <Key, A, E>(options: {
const successor =
entry.pending !== undefined
? makeEntry(entry.pending, entry.explicitWaiter)
: exit._tag === "Failure" && demand._tag === "wake" && !entry.stopping && entry.advisoryRetriesRemaining > 0
? makeEntry(demand, entry.explicitWaiter, entry.advisoryRetriesRemaining - 1)
? makeEntry(entry.pending, { explicitWaiter: entry.explicitWaiter })
: exit._tag === "Failure" && demand._tag === "wake" && !entry.stopping && entry.advisoryRetryAvailable
? makeEntry(demand, { explicitWaiter: entry.explicitWaiter, advisoryRetryAvailable: false })
: undefined
const retrying = successor !== undefined && entry.pending === undefined
if (successor === undefined) active.delete(key)
else active.set(key, successor)
if (successor !== undefined) start(key, successor, successor.current, true)
Deferred.doneUnsafe(entry.done, exit)
Deferred.doneUnsafe(entry.settled, Effect.succeed(exit))
Deferred.doneUnsafe(entry.settled, Effect.succeed(retrying ? undefined : exit))
if (
exit._tag === "Failure" &&
!(entry.stopping && Cause.hasInterruptsOnly(exit.cause)) &&
@ -197,7 +197,7 @@ export const make = <Key, A, E>(options: {
Deferred.await(shutdown).pipe(Effect.as(Exit.void)),
)
if (closed) break
if (exit._tag === "Failure" && firstFailure === undefined) firstFailure = exit.cause
if (exit?._tag === "Failure" && firstFailure === undefined) firstFailure = exit.cause
}
if (firstFailure !== undefined) return yield* Effect.failCause(firstFailure)
})

View file

@ -750,9 +750,10 @@ describe("SessionRunCoordinator", () => {
yield* coordinator.wake("session", 1)
yield* coordinator.wake("session", 2)
yield* Deferred.succeed(firstGate, undefined)
yield* coordinator.awaitIdle("session").pipe(Effect.exit)
const idle = yield* coordinator.awaitIdle("session").pipe(Effect.exit)
expect(runs).toBe(3)
expect(runs).toBe(3)
expect(Exit.isSuccess(idle)).toBeTrue()
}),
),
)