diff --git a/apps/server/src/provider/providerMaintenanceRunner.test.ts b/apps/server/src/provider/providerMaintenanceRunner.test.ts index 641c9b52e56..0e6867e471b 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.test.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.test.ts @@ -109,12 +109,14 @@ function mockHandle(result: { readonly stderr?: string; readonly code?: number; readonly exitCode?: Effect.Effect; + readonly isRunning?: Effect.Effect; + readonly kill?: () => Effect.Effect; }) { return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(1), exitCode: result.exitCode ?? Effect.succeed(ChildProcessSpawner.ExitCode(result.code ?? 0)), - isRunning: Effect.succeed(false), - kill: () => Effect.void, + isRunning: result.isRunning ?? Effect.succeed(false), + kill: result.kill ?? (() => Effect.void), unref: Effect.succeed(Effect.void), stdin: Sink.drain, stdout: Stream.make(encoder.encode(result.stdout ?? "")), @@ -134,6 +136,8 @@ function mockSpawnerLayer( readonly stderr?: string; readonly code?: number; readonly exitCode?: Effect.Effect; + readonly isRunning?: Effect.Effect; + readonly kill?: () => Effect.Effect; }, ) { return Layer.succeed( @@ -217,6 +221,33 @@ const makeTestRunner = (registry: ProviderRegistryShape) => ); describe("providerMaintenanceRunner", () => { + it.effect("does not kill an updater that already exited", () => { + let killCalls = 0; + return Effect.gen(function* () { + const { registry } = yield* makeRegistry(baseCursorProvider); + const updater = yield* makeTestRunner(registry); + + yield* updater.updateProvider(CURSOR_DRIVER); + + assert.strictEqual(killCalls, 0); + }).pipe( + Effect.provide( + Layer.mergeAll( + NonWindowsPlatform, + latestVersionHttpClient("0.0.0"), + mockSpawnerLayer(() => ({ + stdout: "updated", + isRunning: Effect.succeed(false), + kill: () => + Effect.sync(() => { + killCalls += 1; + }), + })), + ), + ), + ); + }); + it.effect("runs the allowlisted provider update command and records success", () => { const calls: Array<{ command: string; args: ReadonlyArray }> = []; return Effect.gen(function* () { diff --git a/apps/server/src/provider/providerMaintenanceRunner.ts b/apps/server/src/provider/providerMaintenanceRunner.ts index 3c114dd83d8..623f9d06b25 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.ts @@ -93,7 +93,13 @@ const runProviderMaintenanceCommandWithSpawner = Effect.fn("ProviderMaintenanceR }), ), ); - yield* Effect.addFinalizer(() => child.kill().pipe(Effect.ignore)); + yield* Effect.addFinalizer(() => + child.isRunning.pipe( + Effect.orElseSucceed(() => true), + Effect.flatMap((isRunning) => (isRunning ? child.kill() : Effect.void)), + Effect.ignore, + ), + ); const [stdout, stderr, exitCode] = yield* Effect.all( [