diff --git a/src/execution/service.ts b/src/execution/service.ts index e8dfe9e60..6085c98b6 100644 --- a/src/execution/service.ts +++ b/src/execution/service.ts @@ -243,6 +243,10 @@ export class ServiceScriptExecution extends BaseExecutionWithCommand { - this._onAbort(); + void this.abort(); }); this._state = { @@ -414,20 +418,16 @@ export class ServiceScriptExecution extends BaseExecutionWithCommand { - this._onAdopteeStopped(); - }); - } + // There is a previous running version of this service, but the + // fingerprint changed, so we need to restart it. + this._state = { + id: 'stoppingAdoptee', + fingerprint, + deferredFingerprint: this._state.deferredFingerprint, + }; + void adoptee.abort().then(() => { + this._onAdopteeStopped(); + }); return; } this._state.deferredFingerprint.resolve({ @@ -724,16 +724,20 @@ export class ServiceScriptExecution extends BaseExecutionWithCommand { switch (this._state.id) { case 'started': { this._state.child.kill(); this._state = {id: 'stopping'}; - return; + break; } case 'starting': { this._state = {id: 'stopping'}; - return; + break; } case 'initial': case 'executingDeps': @@ -742,19 +746,20 @@ export class ServiceScriptExecution extends BaseExecutionWithCommand undefined); } private _enterStoppedState() { diff --git a/src/executor.ts b/src/executor.ts index 7cf53feec..8c1cfba63 100644 --- a/src/executor.ts +++ b/src/executor.ts @@ -137,18 +137,14 @@ export class Executor { currentPersistentServices.add(scriptReferenceToString(script)); } } - const stopPromises = []; + const abortPromises = []; for (const [key, service] of this._previousIterationServices) { if (!currentPersistentServices.has(key)) { - const child = service.detach(); - if (child !== undefined) { - child.kill(); - stopPromises.push(child.completed); - } + abortPromises.push(service.abort()); this._previousIterationServices.delete(key); } } - await Promise.all(stopPromises); + await Promise.all(abortPromises); } const errors: Failure[] = []; diff --git a/src/test/service.test.ts b/src/test/service.test.ts index ce381f8e3..338fe6a74 100644 --- a/src/test/service.test.ts +++ b/src/test/service.test.ts @@ -720,6 +720,7 @@ test( // Iteration 2. We update the config to delete the service. It should get // shut down. + const serviceSigint = IS_WINDOWS ? undefined : serviceInv.interceptSigint(); await rig.writeAtomic({ 'package.json': { scripts: { @@ -736,6 +737,18 @@ test( }, }, }); + if (!IS_WINDOWS) { + // Ensure that we continue to forward stdout/stderr while a stale service + // is being stopped. This won't be the case if we naively detach from the + // first execution, since then we'd stop listening for the output event + // listeners. Note we don't get graceful shutdown in Windows, so just skip + // this in Windows. + await serviceSigint; + serviceInv.stdout('Service shutting down'); + await wireit.waitForLog(/Service shutting down/); + serviceInv.stdout('Service shutting down'); + serviceInv.exit(0); + } await serviceInv.closed; const standardInv2 = await standard.nextInvocation(); standardInv2.exit(0);