响应退出事件/应用程序优雅退出

基于 ClownFish/Nebula 的应用程序,都会响应 Ctrl+C 事件来退出应用程序。

响应 Ctrl+C 事件需要2方面来共同完成:

  • 框架层面,包含基础组件,例如:HttpClient, MessageSubscriber, BackgroundTask
  • 业务代码

目前框架层面已全面支持,本文主要介绍在业务代码中如何 响应 Ctrl+C 事件



调用阻塞等待API

在.NET的框架设计中,绝大多数的阻塞等待API都可以授受一个CancellationToken参数, 它可以 (在程序退出时)提前结束等待。

因此我们可以在调用阻塞方法时,使用这个参数,可供传递的对象有2个(选择其一):

  • ClownFishInit.AppExitToken ,由ClownFish提供
  • AppStartup.AppExitToken ,由Nebula提供

使用示例:

await Task.Delay(waitSeconds * 1000, AppStartup.AppExitToken);
// or
await _channel.Reader.ReadAsync(AppStartup.AppExitToken);

超时时间一起使用:

using CancellationTokenSource timeoutCancelSource = new CancellationTokenSource(timeout);
using CancellationTokenSource tokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutCancelSource.Token, AppStartup.AppExitToken);

var data = await item.Channel.Reader.ReadAsync(tokenSource.Token);



主动判断退出事件

在一个 大循环 中,我们也可以主动去判断有没有触发退出事件,进而提前结束。

示例代码:

if( AppStartup.AppExitToken.IsCancellationRequested ) {
    Console2.WriteLine("Application exit, VenusCommandClient exit.");
    break;
}



注意事项

以下这些设计不会及时响应退出事件

  • Thread.Sleep( 一个长时间 )
  • for/while 中长时间运行,且不检查是否已发生退出事件

如果程序不能及时响应退出事件,那么在超过一段时间后,会被强制中止线程,最后有可能会出现数据损坏。

2个默认的超时时间:

  • asp.net: 30s
  • docker: 10s



检验是否正确响应退出事件

  • 启动程序
  • 稍许等待,让程序所有功能都正常运行 ......
  • 按下 Ctrl+C

观察程序是否立即结束,如果不能,则需要结合具体代码添加埋点处理。