我想通过授权的http请求重启Kestrel(asp.net core 3.1).Kestrel包含在一个Windows服务中,配置为在失败时自动重启自己.据我所知,最简单的方法是返回一个不同于0的退出代码,windows将做所有剩下的事情。
鉴于此,我写的代码其实很简单。
public MaintenanceController(IHostApplicationLifetime hostLifetime)
{
this.HostLifetime = hostLifetime ?? throw new ArgumentNullException(nameof(hostLifetime));
}
[HttpPost]
[Route("service/restart")]
[Authorize("AdminOnly")]
public ActionResult RestartService()
{
Program.IsRestart = true; //see below
this.HostLifetime.StopApplication();
//this does not work!
if (HostLifetime is WindowsServiceLifetime lifetime)
{
lifetime.ExitCode = 1;
}
//neither this!
Environment.ExitCode = 1;
return Ok();
}
唯一能让windows重启服务的方法就是调用
Environment.Exit(1);
而不调用HostLifetime.StopApplication()。
但单独调用Environment.Exit的问题是它会引起一个 非 graceful shutdown,这是我绝对要避免的。
我试过的另一个方法是在Startup.cs.中加入一个不同于0的退出代码,但没有成功。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
{
[...]
applicationLifetime.ApplicationStopped.Register(() =>
{
//this can be set in the controller
if (Program.IsRestart)
{
Environment.Exit(1);
}
});
}
但是,当ApplicationStopped之后调用Environment.Exit(1)时,显然什么都没做,事实上,即使在事件查看器中,也没有服务关闭的痕迹和错误,所以windows什么都没做。
回到经典版,我把Main入口点改成了返回一个int,并返回了1,但windows还是没有重启服务,也没有向事件查看器写入失败记录。它看起来像总是优雅地停止
一切都在正常工作。你可能需要考虑编写一个包装批处理文件或监视程序。
你的监视程序会等待进程退出,如果有一个标志文件(例如. .staydown
)存在,它就会优雅地退出。如果这个文件不存在,它就会重新启动进程。
在你的 RestartService
方法,使用 Environment.Exit(0)
这将是一个优雅的关机,但由于该。.staydown
文件不存在,你的监控器就会重新启动服务器。 您的监控器只有在以下情况下才会停止运行 .staydown
文件存在,然后服务器被停止,或者Windows服务本身被停止。
当您的应用程序启动时,请务必删除 .staydown
如果存在的话。
如果你已经安装了node,你可能可以使用类似于 forever
代替观察者批处理文件。