feat(sdk): expose active sessions (#33991)
This commit is contained in:
parent
40ecfceec2
commit
ef5c9f4931
19 changed files with 233 additions and 68 deletions
|
|
@ -22,9 +22,11 @@ import { testEffect } from "./lib/effect"
|
|||
const executionCalls: SessionV2.ID[] = []
|
||||
const interruptCalls: SessionV2.ID[] = []
|
||||
const wakeCalls: SessionV2.ID[] = []
|
||||
const activeSessions = new Set<SessionV2.ID>()
|
||||
const execution = Layer.succeed(
|
||||
SessionExecution.Service,
|
||||
SessionExecution.Service.of({
|
||||
active: Effect.sync(() => new Set(activeSessions)),
|
||||
resume: (sessionID) =>
|
||||
Effect.sync(() => {
|
||||
executionCalls.push(sessionID)
|
||||
|
|
@ -108,6 +110,13 @@ const eventCount = (type: string) =>
|
|||
)
|
||||
|
||||
describe("SessionV2.prompt", () => {
|
||||
it.effect("exposes the execution registry", () =>
|
||||
Effect.gen(function* () {
|
||||
activeSessions.add(sessionID)
|
||||
expect(Array.from(yield* (yield* SessionV2.Service).active)).toEqual([sessionID])
|
||||
}).pipe(Effect.ensuring(Effect.sync(() => activeSessions.clear()))),
|
||||
)
|
||||
|
||||
it.effect("delegates execution continuation through SessionExecution", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
|
|
|
|||
|
|
@ -66,6 +66,78 @@ describe("SessionRunCoordinator", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("snapshots only active executions", () =>
|
||||
Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const firstStarted = yield* Deferred.make<void>()
|
||||
const secondStarted = yield* Deferred.make<void>()
|
||||
const firstGate = yield* Deferred.make<void>()
|
||||
const secondGate = yield* Deferred.make<void>()
|
||||
const coordinator = yield* SessionRunCoordinator.make({
|
||||
drain: (key: string) =>
|
||||
Deferred.succeed(key === "first" ? firstStarted : secondStarted, undefined).pipe(
|
||||
Effect.andThen(Deferred.await(key === "first" ? firstGate : secondGate)),
|
||||
),
|
||||
})
|
||||
|
||||
expect(Array.from(yield* coordinator.active)).toEqual([])
|
||||
const first = yield* coordinator.run("first").pipe(Effect.forkChild)
|
||||
yield* Deferred.await(firstStarted)
|
||||
expect(Array.from(yield* coordinator.active)).toEqual(["first"])
|
||||
|
||||
const second = yield* coordinator.run("second").pipe(Effect.forkChild)
|
||||
yield* Deferred.await(secondStarted)
|
||||
expect(Array.from(yield* coordinator.active)).toEqual(["first", "second"])
|
||||
|
||||
yield* Deferred.succeed(firstGate, undefined)
|
||||
yield* Fiber.join(first)
|
||||
expect(Array.from(yield* coordinator.active)).toEqual(["second"])
|
||||
yield* Deferred.succeed(secondGate, undefined)
|
||||
yield* Fiber.join(second)
|
||||
expect(Array.from(yield* coordinator.active)).toEqual([])
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
it.effect("cleans active executions after failure and defect", () =>
|
||||
Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const failure = new Error("failed")
|
||||
const defect = new Error("defect")
|
||||
const coordinator = yield* SessionRunCoordinator.make({
|
||||
drain: (key: string) => (key === "failure" ? Effect.fail(failure) : Effect.die(defect)),
|
||||
})
|
||||
|
||||
const failed = yield* coordinator.run("failure").pipe(Effect.exit)
|
||||
expect(Exit.isFailure(failed) && Cause.hasFails(failed.cause)).toBeTrue()
|
||||
expect(Array.from(yield* coordinator.active)).toEqual([])
|
||||
|
||||
const died = yield* coordinator.run("defect").pipe(Effect.exit)
|
||||
expect(Exit.isFailure(died) && Cause.hasDies(died.cause)).toBeTrue()
|
||||
expect(Array.from(yield* coordinator.active)).toEqual([])
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
it.effect("cleans active executions when its scope closes", () =>
|
||||
Effect.gen(function* () {
|
||||
const started = yield* Deferred.make<void>()
|
||||
const coordinator = yield* Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const coordinator = yield* SessionRunCoordinator.make({
|
||||
drain: () => Deferred.succeed(started, undefined).pipe(Effect.andThen(Effect.never)),
|
||||
})
|
||||
yield* coordinator.wake("session")
|
||||
yield* Deferred.await(started)
|
||||
expect(Array.from(yield* coordinator.active)).toEqual(["session"])
|
||||
return coordinator
|
||||
}),
|
||||
)
|
||||
|
||||
expect(Array.from(yield* coordinator.active)).toEqual([])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("coalesces wakes received during active execution", () =>
|
||||
Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -166,6 +238,7 @@ describe("SessionRunCoordinator", () => {
|
|||
|
||||
const exit = yield* Fiber.await(resumed)
|
||||
expect(Exit.isFailure(exit) && Cause.hasInterruptsOnly(exit.cause)).toBeTrue()
|
||||
expect(Array.from(yield* coordinator.active)).toEqual([])
|
||||
expect(runs).toBe(1)
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ const execution = Layer.effect(
|
|||
drain: (sessionID, force) => sessionRunner.run({ sessionID, force }),
|
||||
})
|
||||
return SessionExecution.Service.of({
|
||||
active: coordinator.active,
|
||||
resume: coordinator.run,
|
||||
wake: coordinator.wake,
|
||||
interrupt: coordinator.interrupt,
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ const execution = Layer.effect(
|
|||
drain: (sessionID, force) => sessionRunner.run({ sessionID, force }),
|
||||
})
|
||||
return SessionExecution.Service.of({
|
||||
active: coordinator.active,
|
||||
resume: coordinator.run,
|
||||
wake: coordinator.wake,
|
||||
interrupt: coordinator.interrupt,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue