Reputation: 1362
I need to notify systemd
that my service has started up successfully, and a task it needs to run after startup requires that the server is already listening on the target Unix domain socket.
I am using IWebHost::Run
to start the server, and that is a blocking call. Additionally, I am unable to find any obvious way to set a delegate or callback event for successful initialization.
Anyone?
Upvotes: 11
Views: 4075
Reputation: 8725
A working sample from .NET Core 6:
In your Program.cs, you will have the following (with more or less embellishment, depending on the middleware):
var builder = WebApplication.CreateBuilder(args);
/* ... kestrel configuration, middleware setup ... */
var app = builder.Build();
app.Services.GetService<IHostApplicationLifetime>()!.ApplicationStarted.Register(() =>
{
/* any code you put here will execute
* after the host has started listening */
Console.WriteLine("Kestrel has started listening");
});
/* this is a blocking call.
* the start event occurs from "in there" */
app.Run();
Working principle: The event handler with the Console.WriteLine
call will be called after app.Run()
is already blocking the main thread, at the exact moment when the server is first ready and will accept requests.
Upvotes: 1
Reputation: 9634
This is what I did to overcome the issue.
1- I registered ApplicationStopped
event. So that it brute force terminates the app by calling Kill()
method of the current process.
public void Configure(IHostApplicationLifetime appLifetime) {
appLifetime.ApplicationStarted.Register(() => {
Console.WriteLine("Press Ctrl+C to shut down.");
});
appLifetime.ApplicationStopped.Register(() => {
Console.WriteLine("Terminating application...");
System.Diagnostics.Process.GetCurrentProcess().Kill();
});
}
See IHostApplicationLifetime docs
2- Don't forget to use the UseConsoleLifetime()
while building the host.
Host.CreateDefaultBuilder(args).UseConsoleLifetime(opts => opts.SuppressStatusMessages = true);
Upvotes: 0
Reputation: 1362
This is what I ended up going with, for now. Seems to be working fine:
host.Start();
Log.Information("Press Ctrl+C to shut down...");
Console.CancelKeyPress += OnConsoleCancelKeyPress;
var waitHandles = new WaitHandle[] {
CancelTokenSource.Token.WaitHandle
};
WaitHandle.WaitAll(waitHandles);
Log.Information("Shutting down...");
Then, in the Ctrl+C event handler:
private static void OnConsoleCancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Log.Debug("Got Ctrl+C from console.");
CancelTokenSource.Cancel();
}
Upvotes: 1
Reputation: 49789
You may use Microsoft.AspNetCore.Hosting.IApplicationLifetime:
/// <summary>
/// Triggered when the application host has fully started and is about to wait
/// for a graceful shutdown.
/// </summary>
CancellationToken ApplicationStarted { get; }
Look into this SO post for the configuration example.
Upvotes: 4
Reputation: 15207
On .Net Core 1.x
it is safe to just run IWebHost.Start()
and assume that the server is initialized afterwards (instead of Run()
that blocks the thread). Check the source.
var host = new WebHostBuilder()
.UseKestrel()
(...)
.Build();
host.Start();
If you are using .NET Core 2.0 Preview 1
(or later), the source is different, the synchronous method is not available anymore so you should await IWebHost.StartAsync()
and assume everything is ready afterwards.
Upvotes: 3