Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Shutdown Gracefully on Kill or Interrupt. #327

Merged
merged 16 commits into from Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
56 changes: 52 additions & 4 deletions neo-cli/Services/ConsoleServiceBase.cs
Expand Up @@ -4,9 +4,12 @@
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Security;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Neo.Services
{
Expand All @@ -19,6 +22,10 @@ public abstract class ConsoleServiceBase

protected bool ShowPrompt { get; set; } = true;

private bool _running;
private readonly CancellationTokenSource _shutdownTokenSource = new CancellationTokenSource();
private readonly CountdownEvent _shutdownAcknowledged = new CountdownEvent(1);

protected virtual bool OnCommand(string[] args)
{
switch (args[0].ToLower())
Expand Down Expand Up @@ -211,6 +218,27 @@ public static SecureString ReadSecureString(string prompt)
return securePwd;
}

private void TriggerGracefulShutdown()
{
if (!_running) return;
_running = false;
_shutdownTokenSource.Cancel();
// Wait for us to have triggered shutdown.
_shutdownAcknowledged.Wait();
// Wait slightly longer for the main thread to finish.
Thread.Sleep(100);
}

private void SigTermEventHandler(AssemblyLoadContext obj)
{
TriggerGracefulShutdown();
}

private void CancelHandler(object sender, ConsoleCancelEventArgs e)
{
TriggerGracefulShutdown();
}

public void Run(string[] args)
{
if (Environment.UserInteractive)
Expand Down Expand Up @@ -259,6 +287,7 @@ public void Run(string[] args)
OnStart(args);
RunConsole();
OnStop();
_shutdownAcknowledged.Signal();
}
}
else
Expand All @@ -267,9 +296,28 @@ public void Run(string[] args)
}
}

protected string ReadLine()
{
Task<string> readLineTask = Task.Run(() => Console.ReadLine());
try
{
readLineTask.Wait(_shutdownTokenSource.Token);
}
catch (OperationCanceledException)
{
return null;
}

return readLineTask.Result;
}

private void RunConsole()
{
bool running = true;
_running = true;
// Register sigterm event handler
AssemblyLoadContext.Default.Unloading += SigTermEventHandler;
// Register sigint event handler
Console.CancelKeyPress += CancelHandler;
string[] emptyarg = new string[] { "" };
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
Console.Title = ServiceName;
Expand All @@ -278,7 +326,7 @@ private void RunConsole()
Console.WriteLine($"{ServiceName} Version: {Assembly.GetEntryAssembly().GetVersion()}");
Console.WriteLine();

while (running)
while (_running)
{
if (ShowPrompt)
{
Expand All @@ -287,7 +335,7 @@ private void RunConsole()
}

Console.ForegroundColor = ConsoleColor.Yellow;
string line = Console.ReadLine()?.Trim();
string line = ReadLine()?.Trim();
if (line == null) break;
Console.ForegroundColor = ConsoleColor.White;

Expand All @@ -297,7 +345,7 @@ private void RunConsole()
if (args.Length == 0)
args = emptyarg;

running = OnCommand(args);
_running = OnCommand(args);
}
catch (Exception ex)
{
Expand Down
2 changes: 1 addition & 1 deletion neo-cli/Shell/MainService.cs
Expand Up @@ -953,7 +953,7 @@ private bool OnShowStateCommand(string[] args)
await Task.Delay(500);
}
});
Console.ReadLine();
ReadLine();
stop = true;
task.Wait();
Console.WriteLine();
Expand Down