python购物网站开发流程图,win淘宝客wordpress主题模板,游戏建设网站,郑州建网站公司我最近发现一个问题#xff0c;当应用程序关闭时#xff0c;我们的应用程序没有正确执行在IHostedService中的StopAsync方法。经过反复验证发现#xff0c;这是由于某些服务对关闭信号做出响应所需的时间太长导致的。在这篇文章中#xff0c;我将展示出现这个问题的一个示例… 我最近发现一个问题当应用程序关闭时我们的应用程序没有正确执行在IHostedService中的StopAsync方法。经过反复验证发现这是由于某些服务对关闭信号做出响应所需的时间太长导致的。在这篇文章中我将展示出现这个问题的一个示例并且会讨论它为什么会发生以及如何避免这种情况出现。作者依乐祝首发地址https://www.cnblogs.com/yilezhu/p/12952977.html英文地址https://andrewlock.net/extending-the-shutdown-timeout-setting-to-ensure-graceful-ihostedservice-shutdown/使用IHostedService运行后台服务ASP.NET Core 2.0引入了IHostedService用于运行后台任务的界面。该接口包含两种方法public interface IHostedService
{Task StartAsync(CancellationToken cancellationToken);Task StopAsync(CancellationToken cancellationToken);
}
StartAsync在应用程序启动时被调用。在ASP.NET核心2.X发生这种情况只是之后在应用程序启动处理请求而在ASP.NET核心3.x中托管服务开始只是之前在应用程序启动处理请求。StopAsync当应用程序收到shutdownSIGTERM信号时例如您CTRLC在控制台窗口中按入或者应用程序被主机系统停止时将调用。这样您就可以关闭所有打开的连接处置资源并通常根据需要清理类。实际上实现此接口实际上有一些微妙之处这意味着您通常希望从helper类BackgroundService派生。如果您想了解更多Steve Gordon会开设有关Pluralsight的课程“ 构建ASP.NET Core托管服务和.NET Core Worker Services ”。关闭IHostedService实施的问题我最近看到的问题是OperationCanceledException在应用程序关闭时引发的问题Unhandled exception. System.OperationCanceledException: The operation was canceled.at System.Threading.CancellationToken.ThrowOperationCanceledException()at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)
我将这个问题的根源追溯到一个特定的IHostedService实现。我们将IHostedServices作为每个Kafka消费者的主机。具体操作并不重要-关键在于关闭IHostedService相对较慢取消订阅可能需要几秒钟。问题的一部分是Kafka库和基础librdkafka库使用同步阻塞Consume调用而不是异步可取消调用的方式。解决这个问题的方法不是很好。理解此问题的简便方法是一个示例。演示问题解决此问题的最简单方法是创建一个包含两个IHostedService实现的应用程序NormalHostedService 在启动和关闭时记录日志然后立即返回。SlowHostedService 记录启动和停止的时间但要花10秒才能完成关闭这两个类的实现如下所示。的NormalHostedService很简单public class NormalHostedService : IHostedService
{readonly ILoggerNormalHostedService _logger;public NormalHostedService(ILoggerNormalHostedService logger){_logger logger;}public Task StartAsync(CancellationToken cancellationToken){_logger.LogInformation(NormalHostedService started);return Task.CompletedTask;}public Task StopAsync(CancellationToken cancellationToken){_logger.LogInformation(NormalHostedService stopped);return Task.CompletedTask;}
}
在SlowHostedService几乎是相同的但它有一个Task.Delay是需要10秒以模拟一个缓慢的关机public class SlowHostedService : IHostedService
{readonly ILoggerSlowHostedService _logger;public SlowHostedService(ILoggerSlowHostedService logger){_logger logger;}public Task StartAsync(CancellationToken cancellationToken){_logger.LogInformation(SlowHostedService started);return Task.CompletedTask;}public async Task StopAsync(CancellationToken cancellationToken){_logger.LogInformation(SlowHostedService stopping...);await Task.Delay(10_000);_logger.LogInformation(SlowHostedService stopped);}
}
的IHostedService就是我曾在实践中只用了1秒关机但我们有很多人所以整体效果是一样的上面该服务中注册的顺序ConfigureServices是非常重要的在这种情况下-来证明这个问题我们需要SlowHostedService被关闭第一。服务以相反的顺序关闭这意味着我们需要最后注册它public void ConfigureServices(IServiceCollection services)
{services.AddHostedServiceNormalHostedService();services.AddHostedServiceSlowHostedService();
}
当我们运行该应用程序时您将像往常一样看到启动日志info: ExampleApp.NormalHostedService[0]NormalHostedService started
info: ExampleApp.SlowHostedService[0]SlowHostedService started
...
info: Microsoft.Hosting.Lifetime[0]Application started. Press CtrlC to shut down.
但是如果按CTRLC关闭该应用程序则会出现问题。在SlowHostedService完成关闭但随后一个OperationCanceledException被抛出info: Microsoft.Hosting.Lifetime[0]Application is shutting down...
info: ExampleApp.SlowHostedService[0]SlowHostedService stopping...
info: ExampleApp.SlowHostedService[0]SlowHostedService stoppedUnhandled exception. System.OperationCanceledException: The operation was canceled.at System.Threading.CancellationToken.ThrowOperationCanceledException()at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.WaitForShutdownAsync(IHost host, CancellationToken token)at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)at ExampleApp.Program.Main(String[] args) in C:\repos\andrewlock\blog-examples\SlowShutdown\Program.cs:line 16
该NormalHostedService.StopAsync()方法从不调用。如果该服务需要进行一些清理那么您会遇到问题。例如也许您需要从Consul处优雅地注销该服务或者取消订阅Kafka主题-现在不会发生。那么这是怎么回事超时从哪里来原因HostOptions.ShutDownTimeout您可以在应用程序关闭时运行的框架Host实现中找到有问题的代码。简化的版本如下所示internal class Host: IHost, IAsyncDisposable
{private readonly HostOptions _options;private IEnumerableIHostedService _hostedServices;public async Task StopAsync(CancellationToken cancellationToken default){// Create a cancellation token source that fires after ShutdownTimeout secondsusing (var cts new CancellationTokenSource(_options.ShutdownTimeout))using (var linkedCts CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken)){// Create a token, which is cancelled if the timer expiresvar token linkedCts.Token;// Run StopAsync on each registered hosted serviceforeach (var hostedService in _hostedServices.Reverse()){// stop calling StopAsync if timer expirestoken.ThrowIfCancellationRequested();try{await hostedService.StopAsync(token).ConfigureAwait(false);}catch (Exception ex){exceptions.Add(ex);}}}// .. other stopping code}
}
这里的关键点CancellationTokenSource是配置为HostOptions.ShutdownTimeout之后触发的。默认情况下这会在5秒后触发。这意味着5秒后将放弃托管服务关闭- IHostedService必须在此超时内关闭所有托管服务。public class HostOptions
{public TimeSpan ShutdownTimeout { get; set; } TimeSpan.FromSeconds(5);
}
在foreach循环的第一次迭代中SlowHostedService.Stopasync()执行需要10秒钟才能运行。在第二次迭代中超过了5s超时因此token.ThrowIfCancellationRequested();抛出OperationConcelledException。这将退出控制流并且NormalHostedService.Stopasync()永远不会执行。有一个简单的解决方案-增加shutdown超时时间解决方法增加shutdown超时时间HostOptions默认情况下未在任何地方显式配置它因此您需要在ConfigureSerices方法中手动对其进行配置。例如以下配置将超时增加到15spublic void ConfigureServices(IServiceCollection services)
{services.AddHostedServiceNormalHostedService();services.AddHostedServiceSlowShutdownHostedService();// Configure the shutdown to 15sservices.ConfigureHostOptions(opts opts.ShutdownTimeout TimeSpan.FromSeconds(15));
}
或者您也可以从配置中加载超时时间。例如如果将以下内容添加到appsettings.json{HostOptions: {ShutdownTimeout: 00:00:15}// other config
}
然后您可以将HostOptions配置部分绑定到HostOptions对象public class Startup
{public IConfiguration Configuration { get; }public Startup(IConfiguration configuration){Configuration configuration;}public void ConfigureServices(IServiceCollection services){services.AddHostedServiceNormalHostedService();services.AddHostedServiceSlowShutdownHostedService();// bind the config to host optionsservices.ConfigureHostOptions(Configuration.GetSection(HostOptions));}
}
这会将序列化的TimeSpan值绑定00:00:15到该HostOptions值并将超时间设置为15s。使用该配置现在当我们停止应用程序时所有服务都将正确关闭nfo: Microsoft.Hosting.Lifetime[0]Application is shutting down...
info: SlowShutdown.SlowShutdownHostedService[0]SlowShutdownHostedService stopping...
info: SlowShutdown.SlowShutdownHostedService[0]SlowShutdownHostedService stopped
info: SlowShutdown.NormalHostedService[0]NormalHostedService stopped
现在您的应用程序将等待15秒以使所有托管服务在退出之前完成关闭摘要在这篇文章中我讨论了一个最近发现的问题该问题是当应用程序关闭时我们的应用程序未在IHostedService实现中的StopAsync中运行该方法。这是由于某些后台服务对关闭信号做出响应所需的时间太长并且超过了关闭超时时间。文中我演示了单个服务需要10秒才能关闭服务来重现问题但实际上只要所有服务的总关闭时间超过默认5秒就会发生此问题。该问题的解决方案是HostOptions.ShutdownTimeout使用标准ASP.NET Core IOptionsT配置系统将配置值扩展为超过5s 。往期精彩回顾【推荐】.NET Core开发实战视频课程 ★★★.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划【.NET Core微服务实战-统一身份认证】开篇及目录索引Redis基本使用及百亿数据量中的使用技巧分享附视频地址及观看指南.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了10个小技巧助您写出高性能的ASP.NET Core代码用abp vNext快速开发Quartz.NET定时任务管理界面在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度现身说法实际业务出发分析百亿数据量下的多表查询优化关于C#异步编程你应该了解的几点建议C#异步编程看这篇就够了给我好看
您看此文用 · 秒转发只需1秒呦~
好看你就点点我