fix(installer): wait for prior service registration to clear before create
After `sc delete`, the service stays in "marked for deletion" state until every open handle (services.msc, Task Manager Services tab, Event Viewer, prior sc query process) is closed. The installer used to immediately call `sc create` and hit a silent hang / confusing "specified service has been marked for deletion" error. Poll `sc query` for up to 30s after delete; if the service is still registered past that, fail with actionable guidance (close the offending console or reboot). Also translate exit 1072 from `sc create` into the same human-readable hint. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,24 @@ public sealed class RegisterServiceStep : IInstallStep
|
|||||||
progress.Report("Removing existing service registration (if any)...");
|
progress.Report("Removing existing service registration (if any)...");
|
||||||
await RunSc($"delete {ServiceName}", ctx, progress, ct, ignoreErrors: true);
|
await RunSc($"delete {ServiceName}", ctx, progress, ct, ignoreErrors: true);
|
||||||
|
|
||||||
|
// Wait for the service to actually disappear from SCM. `sc delete` returns
|
||||||
|
// immediately but the service stays "marked for deletion" until every open
|
||||||
|
// handle (services.msc, Task Manager, a prior sc query process) is closed.
|
||||||
|
// Poll up to 30s — then fail with actionable guidance if it's still there.
|
||||||
|
progress.Report("Waiting for prior service registration to clear...");
|
||||||
|
for (var i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
var (queryExit, _) = await RunSc($"query {ServiceName}", ctx, progress, ct, ignoreErrors: true);
|
||||||
|
if (queryExit != 0) break; // service no longer registered — good
|
||||||
|
if (i == 29)
|
||||||
|
return StepResult.Fail(
|
||||||
|
$"Service '{ServiceName}' is marked for deletion but hasn't cleared after 30s. " +
|
||||||
|
"Close any open Services console (services.msc), Task Manager Services tab, or " +
|
||||||
|
"Event Viewer showing the service, then retry. A reboot will also clear it.");
|
||||||
|
await Task.Delay(1000, ct);
|
||||||
|
}
|
||||||
|
|
||||||
// Create service
|
// Create service
|
||||||
var startType = ctx.AutoStart ? "auto" : "demand";
|
var startType = ctx.AutoStart ? "auto" : "demand";
|
||||||
var createArgs = $"create {ServiceName} binPath= \"{workerExe}\" start= {startType}";
|
var createArgs = $"create {ServiceName} binPath= \"{workerExe}\" start= {startType}";
|
||||||
@@ -35,6 +53,10 @@ public sealed class RegisterServiceStep : IInstallStep
|
|||||||
|
|
||||||
progress.Report("Creating service...");
|
progress.Report("Creating service...");
|
||||||
var (exitCode, output) = await RunSc(createArgs, ctx, progress, ct);
|
var (exitCode, output) = await RunSc(createArgs, ctx, progress, ct);
|
||||||
|
if (exitCode == 1072)
|
||||||
|
return StepResult.Fail(
|
||||||
|
$"Service '{ServiceName}' is still marked for deletion. " +
|
||||||
|
"Close services.msc / Task Manager / Event Viewer and retry, or reboot.");
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
return StepResult.Fail($"sc.exe create failed (exit {exitCode}): {output}");
|
return StepResult.Fail($"sc.exe create failed (exit {exitCode}): {output}");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user