Skip to content

Commit dd59538

Browse files
kitlangtontimrichardson
authored andcommitted
refactor(effect): drop shell abort signals from runner (anomalyco#21599)
1 parent 8048467 commit dd59538

File tree

3 files changed

+22
-58
lines changed

3 files changed

+22
-58
lines changed

packages/opencode/src/effect/runner.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { Cause, Deferred, Effect, Exit, Fiber, Option, Schema, Scope, SynchronizedRef } from "effect"
1+
import { Cause, Deferred, Effect, Exit, Fiber, Schema, Scope, SynchronizedRef } from "effect"
22

33
export interface Runner<A, E = never> {
44
readonly state: Runner.State<A, E>
55
readonly busy: boolean
66
readonly ensureRunning: (work: Effect.Effect<A, E>) => Effect.Effect<A, E>
7-
readonly startShell: (work: (signal: AbortSignal) => Effect.Effect<A, E>) => Effect.Effect<A, E>
7+
readonly startShell: (work: Effect.Effect<A, E>) => Effect.Effect<A, E>
88
readonly cancel: Effect.Effect<void>
99
}
1010

@@ -20,7 +20,6 @@ export namespace Runner {
2020
interface ShellHandle<A, E> {
2121
id: number
2222
fiber: Fiber.Fiber<A, E>
23-
abort: AbortController
2423
}
2524

2625
interface PendingHandle<A, E> {
@@ -100,13 +99,7 @@ export namespace Runner {
10099
}),
101100
).pipe(Effect.flatten)
102101

103-
const stopShell = (shell: ShellHandle<A, E>) =>
104-
Effect.gen(function* () {
105-
shell.abort.abort()
106-
const exit = yield* Fiber.await(shell.fiber).pipe(Effect.timeoutOption("100 millis"))
107-
if (Option.isNone(exit)) yield* Fiber.interrupt(shell.fiber)
108-
yield* Fiber.await(shell.fiber).pipe(Effect.exit, Effect.asVoid)
109-
})
102+
const stopShell = (shell: ShellHandle<A, E>) => Fiber.interrupt(shell.fiber)
110103

111104
const ensureRunning = (work: Effect.Effect<A, E>) =>
112105
SynchronizedRef.modifyEffect(
@@ -138,7 +131,7 @@ export namespace Runner {
138131
),
139132
)
140133

141-
const startShell = (work: (signal: AbortSignal) => Effect.Effect<A, E>) =>
134+
const startShell = (work: Effect.Effect<A, E>) =>
142135
SynchronizedRef.modifyEffect(
143136
ref,
144137
Effect.fnUntraced(function* (st) {
@@ -153,9 +146,8 @@ export namespace Runner {
153146
}
154147
yield* busy
155148
const id = next()
156-
const abort = new AbortController()
157-
const fiber = yield* work(abort.signal).pipe(Effect.ensuring(finishShell(id)), Effect.forkChild)
158-
const shell = { id, fiber, abort } satisfies ShellHandle<A, E>
149+
const fiber = yield* work.pipe(Effect.ensuring(finishShell(id)), Effect.forkChild)
150+
const shell = { id, fiber } satisfies ShellHandle<A, E>
159151
return [
160152
Effect.gen(function* () {
161153
const exit = yield* Fiber.await(fiber)

packages/opencode/src/session/prompt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
743743
} satisfies MessageV2.TextPart)
744744
})
745745

746-
const shellImpl = Effect.fn("SessionPrompt.shellImpl")(function* (input: ShellInput, signal: AbortSignal) {
746+
const shellImpl = Effect.fn("SessionPrompt.shellImpl")(function* (input: ShellInput) {
747747
const ctx = yield* InstanceState.context
748748
const session = yield* sessions.get(input.sessionID)
749749
if (session.revert) {
@@ -1577,7 +1577,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
15771577
function* (input: ShellInput) {
15781578
const s = yield* InstanceState.get(state)
15791579
const runner = getRunner(s.runners, input.sessionID)
1580-
return yield* runner.startShell((signal) => shellImpl(input, signal))
1580+
return yield* runner.startShell(shellImpl(input))
15811581
},
15821582
)
15831583

packages/opencode/test/effect/runner.test.ts

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ describe("Runner", () => {
250250
Effect.gen(function* () {
251251
const s = yield* Scope.Scope
252252
const runner = Runner.make<string>(s)
253-
const result = yield* runner.startShell((_signal) => Effect.succeed("shell-done"))
253+
const result = yield* runner.startShell(Effect.succeed("shell-done"))
254254
expect(result).toBe("shell-done")
255255
expect(runner.busy).toBe(false)
256256
}),
@@ -264,7 +264,7 @@ describe("Runner", () => {
264264
const fiber = yield* runner.ensureRunning(Effect.never.pipe(Effect.as("x"))).pipe(Effect.forkChild)
265265
yield* Effect.sleep("10 millis")
266266

267-
const exit = yield* runner.startShell((_s) => Effect.succeed("nope")).pipe(Effect.exit)
267+
const exit = yield* runner.startShell(Effect.succeed("nope")).pipe(Effect.exit)
268268
expect(Exit.isFailure(exit)).toBe(true)
269269

270270
yield* runner.cancel
@@ -279,12 +279,10 @@ describe("Runner", () => {
279279
const runner = Runner.make<string>(s)
280280
const gate = yield* Deferred.make<void>()
281281

282-
const sh = yield* runner
283-
.startShell((_signal) => Deferred.await(gate).pipe(Effect.as("first")))
284-
.pipe(Effect.forkChild)
282+
const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("first"))).pipe(Effect.forkChild)
285283
yield* Effect.sleep("10 millis")
286284

287-
const exit = yield* runner.startShell((_s) => Effect.succeed("second")).pipe(Effect.exit)
285+
const exit = yield* runner.startShell(Effect.succeed("second")).pipe(Effect.exit)
288286
expect(Exit.isFailure(exit)).toBe(true)
289287

290288
yield* Deferred.succeed(gate, undefined)
@@ -302,37 +300,26 @@ describe("Runner", () => {
302300
},
303301
})
304302

305-
const sh = yield* runner
306-
.startShell((signal) =>
307-
Effect.promise(
308-
() =>
309-
new Promise<string>((resolve) => {
310-
signal.addEventListener("abort", () => resolve("aborted"), { once: true })
311-
}),
312-
),
313-
)
314-
.pipe(Effect.forkChild)
303+
const sh = yield* runner.startShell(Effect.never.pipe(Effect.as("aborted"))).pipe(Effect.forkChild)
315304
yield* Effect.sleep("10 millis")
316305

317-
const exit = yield* runner.startShell((_s) => Effect.succeed("second")).pipe(Effect.exit)
306+
const exit = yield* runner.startShell(Effect.succeed("second")).pipe(Effect.exit)
318307
expect(Exit.isFailure(exit)).toBe(true)
319308

320309
yield* runner.cancel
321310
const done = yield* Fiber.await(sh)
322-
expect(Exit.isSuccess(done)).toBe(true)
311+
expect(Exit.isFailure(done)).toBe(true)
323312
}),
324313
)
325314

326315
it.live(
327-
"cancel interrupts shell that ignores abort signal",
316+
"cancel interrupts shell",
328317
Effect.gen(function* () {
329318
const s = yield* Scope.Scope
330319
const runner = Runner.make<string>(s)
331320
const gate = yield* Deferred.make<void>()
332321

333-
const sh = yield* runner
334-
.startShell((_signal) => Deferred.await(gate).pipe(Effect.as("ignored")))
335-
.pipe(Effect.forkChild)
322+
const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("ignored"))).pipe(Effect.forkChild)
336323
yield* Effect.sleep("10 millis")
337324

338325
const stop = yield* runner.cancel.pipe(Effect.forkChild)
@@ -356,9 +343,7 @@ describe("Runner", () => {
356343
const runner = Runner.make<string>(s)
357344
const gate = yield* Deferred.make<void>()
358345

359-
const sh = yield* runner
360-
.startShell((_signal) => Deferred.await(gate).pipe(Effect.as("shell-result")))
361-
.pipe(Effect.forkChild)
346+
const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("shell-result"))).pipe(Effect.forkChild)
362347
yield* Effect.sleep("10 millis")
363348
expect(runner.state._tag).toBe("Shell")
364349

@@ -384,9 +369,7 @@ describe("Runner", () => {
384369
const calls = yield* Ref.make(0)
385370
const gate = yield* Deferred.make<void>()
386371

387-
const sh = yield* runner
388-
.startShell((_signal) => Deferred.await(gate).pipe(Effect.as("shell")))
389-
.pipe(Effect.forkChild)
372+
const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("shell"))).pipe(Effect.forkChild)
390373
yield* Effect.sleep("10 millis")
391374

392375
const work = Effect.gen(function* () {
@@ -414,16 +397,7 @@ describe("Runner", () => {
414397
const runner = Runner.make<string>(s)
415398
const gate = yield* Deferred.make<void>()
416399

417-
const sh = yield* runner
418-
.startShell((signal) =>
419-
Effect.promise(
420-
() =>
421-
new Promise<string>((resolve) => {
422-
signal.addEventListener("abort", () => resolve("aborted"), { once: true })
423-
}),
424-
),
425-
)
426-
.pipe(Effect.forkChild)
400+
const sh = yield* runner.startShell(Effect.never.pipe(Effect.as("aborted"))).pipe(Effect.forkChild)
427401
yield* Effect.sleep("10 millis")
428402

429403
const run = yield* runner.ensureRunning(Effect.succeed("y")).pipe(Effect.forkChild)
@@ -478,7 +452,7 @@ describe("Runner", () => {
478452
const runner = Runner.make<string>(s, {
479453
onBusy: Ref.update(count, (n) => n + 1),
480454
})
481-
yield* runner.startShell((_signal) => Effect.succeed("done"))
455+
yield* runner.startShell(Effect.succeed("done"))
482456
expect(yield* Ref.get(count)).toBe(1)
483457
}),
484458
)
@@ -509,9 +483,7 @@ describe("Runner", () => {
509483
const runner = Runner.make<string>(s)
510484
const gate = yield* Deferred.make<void>()
511485

512-
const fiber = yield* runner
513-
.startShell((_signal) => Deferred.await(gate).pipe(Effect.as("ok")))
514-
.pipe(Effect.forkChild)
486+
const fiber = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("ok"))).pipe(Effect.forkChild)
515487
yield* Effect.sleep("10 millis")
516488
expect(runner.busy).toBe(true)
517489

0 commit comments

Comments
 (0)