Skip to content
Prev Previous commit
Next Next commit
Avoid calling ServiceBase.Stop on stopped service
I fixed double-calling STATE_STOPPED in ServiceBase, but this fix will
not be present on .NETFramework.  Workaround that by avoiding calling
ServiceBase.Stop when the service has already been stopped by SCM.
  • Loading branch information
ericstj committed Mar 29, 2023
commit e6de2e1340cf8b1a94d0e6f5079e20a29967c2e8
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class WindowsServiceLifetime : ServiceBase, IHostLifetime
private readonly TaskCompletionSource<object?> _serviceStopped = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);
private readonly ManualResetEventSlim _delayStop = new ManualResetEventSlim();
private readonly HostOptions _hostOptions;
private bool _isStopped;

/// <summary>
/// Initializes a new <see cref="WindowsServiceLifetime"/> instance.
Expand Down Expand Up @@ -98,8 +99,12 @@ private void Run()

public Task StopAsync(CancellationToken cancellationToken)
{
// Stop will cause the ServiceBase.Run method to complete and return, which completes _serviceStopped.
Task.Run(Stop, CancellationToken.None);
if (!_isStopped)
{
Task.Run(Stop, CancellationToken.None);
}

// When the underlying service is stopped this will cause the ServiceBase.Run method to complete and return, which completes _serviceStopped.
return _serviceStopped.Task;
}

Expand All @@ -117,6 +122,7 @@ protected override void OnStart(string[] args)
/// <remarks>This might be called multiple times by service Stop, ApplicationStopping, and StopAsync. That's okay because StopApplication uses a CancellationTokenSource and prevents any recursion.</remarks>
protected override void OnStop()
{
_isStopped = true;
ApplicationLifetime.StopApplication();
// Wait for the host to shutdown before marking service as stopped.
_delayStop.Wait(_hostOptions.ShutdownTimeout);
Expand All @@ -128,6 +134,7 @@ protected override void OnStop()
/// </summary>
protected override void OnShutdown()
{
_isStopped = true;
ApplicationLifetime.StopApplication();
// Wait for the host to shutdown before marking service as stopped.
_delayStop.Wait(_hostOptions.ShutdownTimeout);
Expand Down