I have a process which I'm porting from Windows to Linux, and I need it to restart relatively promptly when I call systemctl restart service. Unfortunately, it hangs for the 90 second timeout which is unacceptable.
I've tried several things without effect. Notably, I have added a handler for Domain.CurrentDomain.ProcessExit
in my Program.cs file, but that handler never gets hit when I send that command, or any other as far as I can tell. I have reviewed the answers for this question, this question, and this question. I am using IHostBuilder to do this, but I am not in a container. I'm running on Debian 11. I have a background service which implements ExecuteAsync
, but it has never served to shut down the service. Even running it from the console and using Ctrl-C doesn't result in the signal handler being called (and in fact doesn't actually terminate the process, even giving it the usual 90 second delay). What am I missing?
This is my Main function and its helpers. When I manually set kill to true via debugger, the program exits (albeit ungracefully). Letting the system run without the exception results in the same hanging behavior. Clearly one of the many threads is hanging onto resources, but they should be guarded with cancellation tokens, which as previously stated are not working.
public static async Task Main(string[] args)
{
IHost builder = CreateHostBuilder(args).Build();
bool kill = false;
void OnCurrentDomainOnProcessExit(object sender, EventArgs args)
{
kill = true;
}
AppDomain.CurrentDomain.ProcessExit +=
OnCurrentDomainOnProcessExit;
await builder.StartAsync();
while (!kill)
{
Thread.Sleep(1000);
}
await builder.StopAsync(TimeSpan.FromSeconds(10));
throw new Exception("Received SIGTERM");
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSystemd()
.UseConsoleLifetime()
.ConfigureServices(ConfigureServices);
private static void ConfigureServices(HostBuilderContext _, IServiceCollection services)
{
services.AddLogging();
services.AddSingleton<ITheSingleton, TheSingleton>();
services.AddHostedService<ProcessWorker>();
}
Here's my simple implementation of a BackgroundService:
public class ProcessWorker: BackgroundService
{
ITheProcess _process;
public ProcessWorker(ITheProcess process)
{
_process = process;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}