响应退出事件/应用程序优雅退出
基于 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
观察程序是否立即结束,如果不能,则需要结合具体代码添加埋点处理。