Kestrel何时开始监听,我该如何知道?

10
我需要通知systemd我的服务已经成功启动,而且启动后需要运行的任务要求服务器已经在目标Unix域套接字上正在监听

我正在使用IWebHost::Run来启动服务器,这是一个阻塞调用。此外,我无法找到任何明显的方法来设置成功初始化的委托或回调事件。

有人能帮忙吗?

5个回答

4

您可以使用 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; }

请查看此SO post,以获取配置示例。


3
  • 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.


这就是我最终所做的;关于Start()是异步的评论只是错误的。 - aremmell

1

目前我采用了这个方案,看起来运行良好:

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...");

然后,在Ctrl+C事件处理程序中:
private static void OnConsoleCancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
    Log.Debug("Got Ctrl+C from console.");
    CancelTokenSource.Cancel();
}

7
这段代码如何帮助您检测Kestrel何时完成初始化? - Gerardo Grignoli
你不是说在调用Start()之后可以安全地假设Kestrel已经准备好了吗,除非我使用的是2.0预览版1?那个有关它是异步的评论不应该存在。 - aremmell
我之所以问是因为我不知道,而且你的回答对我来说不够清晰。我以为你是通过黑客手段来检测初始化结束的取消事件。后来我做了一些研究,发现Start是安全的,所以我发了帖子,并假设你的代码能奇迹般地工作,如果真的有的话。现在我相信你已经正确地编写了如何阻止当前线程的代码。如果你的回答中有一些措辞,所有的误解都可以避免。 - Gerardo Grignoli

1

一个来自.NET Core 6的工作示例:

在您的Program.cs中,您将拥有以下内容(根据中间件的多少,可能会更加或更少地装饰):

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();

工作原理:带有Console.WriteLine调用的事件处理程序将在app.Run()已经阻塞主线程的情况下被调用,在服务器第一次准备好并接受请求的确切时刻。

这个回答如何回答问题? - DavidG
1
你知道kestrel已经开始监听的方法。 - Cee McSharpface

0
这是我为解决问题所做的事情。
1- 我注册了 ApplicationStopped 事件。这样它就可以通过调用当前进程的 Kill() 方法来强制终止应用程序。
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();
 });
}

查看 IHostApplicationLifetime 文档


2- 构建主机时不要忘记使用 UseConsoleLifetime()

Host.CreateDefaultBuilder(args).UseConsoleLifetime(opts => opts.SuppressStatusMessages = true);

查看 useconsolelifetime 文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接