.NET之Kill -15 优雅退出
背景:运维人员在每次进行代码升级版本的时候,会执行kill 命令关闭进程,再上传代码包。这时候会出现以下问题:
1. 已接收的HTTP请求业务没有处理完成就立即停止进程
如果让程序自动处理完业务后关闭进程会出现以下问题:
1. 拒绝接收新的HTTP请求消息
以下截图是本机代码测试:

using D.TestKill15;
using D.TestKill15.NLogsUtil;
var builder = WebApplication.CreateBuilder(args);
// NLog 日志
builder.Services.AddNLogUtil();
builder.Services.AddControllers();
//builder.Services.AddHealthChecks();微软的探针,查看服务是否存活
builder.WebHost.UseKestrel(o =>
{
o.ListenAnyIP(5000);
});
var app = builder.Build();
var nlog = app.Services.GetService<INLogService>();
if (args.Length > 0)
{
await Console.Out.WriteLineAsync($"开始输出args参数,共{args.Length}个");
nlog.Info($"开始输出args参数,共{args.Length}个");
foreach (var arg in args)
{
await Console.Out.WriteLineAsync(arg);
nlog.Info(arg);
}
}
else
{
await Console.Out.WriteLineAsync($"args入参长度为{args.Length}");
nlog.Info($"args入参长度为{args.Length}");
}
int requestCount = 0;
bool isExit = false;
app.Use(async (httpContext, next) =>
{
await Console.Out.WriteLineAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-收到HTTP请求-{requestCount}");
if (isExit)
{
await Console.Out.WriteLineAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-已收到退出程序指令,程序正在退出,拒绝接受新消息");
httpContext.Abort();
}
else
{
Interlocked.Increment(ref requestCount);
try
{
await next();
}
finally
{
Interlocked.Decrement(ref requestCount);
}
}
});
// 收到关闭请求
app.Lifetime.ApplicationStopping.Register(async () =>
{
await Console.Out.WriteLineAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-ApplicationStopping start");
isExit = true;
SpinWait.SpinUntil(() => requestCount == 0);
//Console.Out.WriteLineAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-等待{20000/1000}s后再关闭");
//Thread.Sleep(20000); 另外一种方案,延迟多少ms后,自动关闭
//Console.Out.WriteLineAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-等待完成,执行关闭");
});
// 执行关闭
app.Lifetime.ApplicationStopped.Register(async () =>
{
await Console.Out.WriteLineAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-ApplicationStopped start");
});
app.MapControllers();
//app.MapHealthChecks("/healthz");
app.Run();
using D.TestKill15.NLogsUtil;
using Microsoft.AspNetCore.Mvc;
namespace D.TestKill15
{
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
INLogService _nLogService;
public TestController(INLogService nLogService)
{
_nLogService = nLogService;
}
[HttpGet("get")]
public async Task<string> Get(int? delayTime)
{
var t = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-收到消息";
_nLogService.Info(t);
await Console.Out.WriteLineAsync(t);
if (delayTime != null)
{
var s = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-开始执行函数需要耗费{delayTime}ms";
_nLogService.Info(s);
await Console.Out.WriteLineAsync(s);
await Task.Delay(delayTime.Value);
var e = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}-函数执行{delayTime}ms完毕";
_nLogService.Info(e);
await Console.Out.WriteLineAsync(e);
}
var r = $"返回消息:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}";
await Console.Out.WriteLineAsync(r);
return r;
}
}
}
彪悍的人生不需要解释,彪悍的代码不需要注释。

浙公网安备 33010602011771号