| author | |
| committer | |
| log | 7722cb6d2e44e0aeb136a86bc2165f1cc733146a |
| tree | 9f7c5c665666f31078ecf37a24eea790ec746b8d |
| parent | c9a59a26bb85902b9b2e828e1f99cc0760105ae4 |
- make integration harness dispose path always remove temp root dirs via `Effect.ensuring`
- preserve shutdown failure by surfacing the first teardown error cause
- add integration test that forces `providerService.stopAll` failure and verifies temp dir cleanup2 files changed, 48 insertions(+), 6 deletions(-)
apps/server/integration/OrchestrationEngineHarness.integration.ts+29-5| ... | ... | @@ -317,12 +317,36 @@ export const makeOrchestrationIntegrationHarness = Effect.gen(function* () { |
| 317 | 317 | } |
| 318 | 318 | disposed = true; |
| 319 | 319 | |
| 320 | yield* Effect.promise(() => runtime.runPromise(providerService.stopAll())); | |
| 321 | yield* Effect.promise(() => Effect.runPromise(Scope.close(scope, Exit.void))); | |
| 322 | yield* Effect.promise(() => runtime.dispose()); | |
| 323 | yield* Effect.sync(() => { | |
| 324 | fs.rmSync(rootDir, { recursive: true, force: true }); | |
| 320 | const shutdown = Effect.gen(function* () { | |
| 321 | const stopAllExit = yield* Effect.exit( | |
| 322 | Effect.promise(() => runtime.runPromise(providerService.stopAll())), | |
| 323 | ); | |
| 324 | const closeScopeExit = yield* Effect.exit( | |
| 325 | Effect.promise(() => Effect.runPromise(Scope.close(scope, Exit.void))), | |
| 326 | ); | |
| 327 | const disposeRuntimeExit = yield* Effect.exit(Effect.promise(() => runtime.dispose())); | |
| 328 | ||
| 329 | const failureCause = | |
| 330 | Exit.isFailure(stopAllExit) | |
| 331 | ? stopAllExit.cause | |
| 332 | : Exit.isFailure(closeScopeExit) | |
| 333 | ? closeScopeExit.cause | |
| 334 | : Exit.isFailure(disposeRuntimeExit) | |
| 335 | ? disposeRuntimeExit.cause | |
| 336 | : null; | |
| 337 | ||
| 338 | if (failureCause) { | |
| 339 | yield* Effect.failCause(failureCause); | |
| 340 | } | |
| 325 | 341 | }); |
| 342 | ||
| 343 | yield* shutdown.pipe( | |
| 344 | Effect.ensuring( | |
| 345 | Effect.sync(() => { | |
| 346 | fs.rmSync(rootDir, { recursive: true, force: true }); | |
| 347 | }), | |
| 348 | ), | |
| 349 | ); | |
| 326 | 350 | }); |
| 327 | 351 | |
| 328 | 352 | return { |
apps/server/integration/orchestrationEngine.integration.test.ts+19-1| ... | ... | @@ -13,7 +13,7 @@ import { |
| 13 | 13 | ThreadId, |
| 14 | 14 | } from "@t3tools/contracts"; |
| 15 | 15 | import { assert, it } from "@effect/vitest"; |
| 16 | import { Effect, Option } from "effect"; | |
| 16 | import { Effect, Exit, Option } from "effect"; | |
| 17 | 17 | |
| 18 | 18 | import type { TestTurnResponse } from "./TestProviderAdapter.integration.ts"; |
| 19 | 19 | import { |
| ... | ... | @@ -133,6 +133,24 @@ const startTurn = (input: { |
| 133 | 133 | createdAt: nowIso(), |
| 134 | 134 | }); |
| 135 | 135 | |
| 136 | it.live("always removes integration temp dirs when shutdown fails", () => | |
| 137 | Effect.gen(function* () { | |
| 138 | const harness = yield* makeOrchestrationIntegrationHarness; | |
| 139 | const rootDir = harness.rootDir; | |
| 140 | const originalStopAll = harness.providerService.stopAll.bind(harness.providerService); | |
| 141 | ||
| 142 | ( | |
| 143 | harness.providerService as unknown as { | |
| 144 | stopAll: typeof harness.providerService.stopAll; | |
| 145 | } | |
| 146 | ).stopAll = () => originalStopAll().pipe(Effect.andThen(Effect.fail(new Error("boom")))); | |
| 147 | ||
| 148 | const disposeExit = yield* Effect.exit(harness.dispose); | |
| 149 | assert.equal(Exit.isFailure(disposeExit), true); | |
| 150 | assert.equal(fs.existsSync(rootDir), false); | |
| 151 | }), | |
| 152 | ); | |
| 153 | ||
| 136 | 154 | it.live("runs a single turn end-to-end and persists checkpoint state in sqlite + git", () => |
| 137 | 155 | withHarness((harness) => |
| 138 | 156 | Effect.gen(function* () { |