.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;
        }
    }
}

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章