.NET Core基于Generic Host实现后台任务方法教程(4)

[Unit] Description=Generic Host Demo [Service] WorkingDirectory=https://www.jb51.net/var/www/ghost ExecStart=https://www.jb51.net/usr/bin/dotnet /var/www/ghost/ConsoleGHost.dll --environment Staging KillSignal=SIGINT SyslogIdentifier=ghost-example [Install] WantedBy=multi-user.target

其中,各项配置的含义可以自行查找,这里不作说明。

然后可以通过下面的命令来启动和停止这个服务

service ghostdemo start service ghostdemo stop

测试无误之后,就可以设为自启动了。

systemctl enable ghostdemo.service

下面来看看运行的效果

.NET Core基于Generic Host实现后台任务方法教程

我们先启动服务,然后去查看实时日志,可以看到应用的日志不停的输出。

当我们停了服务,再看实时日志,就会发现我们的两个后台任务已经停止了,也没有日志再进来了。

再去看看服务系统日志

sudo journalctl -fu ghostdemo.service

.NET Core基于Generic Host实现后台任务方法教程

发现它确实也是停了。

在这里,我们还可以看到服务的当前环境和根路径。

IHostedService和BackgroundService的区别

前面的所有示例中,我们用的都是BackgroundService,而不是IHostedService。

这两者有什么区别呢?

可以这样简单的理解,IHostedService是原料,BackgroundService是一个用原料加工过一部分的半成品。

这两个都是不能直接当成成品来用的,都需要进行加工才能做成一个可用的成品。

同时也意味着,如果使用IHostedService可能会需要做比较多的控制。

基于前面的打印后台任务,在这里使用IHostedService来实现。

如果我们只是纯綷的把实现代码放到StartAsync方法中,那么可能就会有惊喜了。

public class PrinterHostedService : IHostedService, IDisposable { //other .... public async Task StartAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { Console.WriteLine("Printer is working."); await Task.Delay(TimeSpan.FromSeconds(_settings.PrinterDelaySecond), cancellationToken); } } public Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("Printer is stopped"); return Task.CompletedTask; } }

运行之后,想用ctrl+c来停止,发现还是一直在跑。

.NET Core基于Generic Host实现后台任务方法教程

ps一看,这个进程还在,kill掉之后才不会继续输出。。

.NET Core基于Generic Host实现后台任务方法教程

问题出在那里呢?原因其实还是比较明显的,因为这个任务还没有启动成功,一直处于启动中的状态!

换句话说,StartAsync方法还没有执行完。这个问题一定要小心再小心。

要怎么处理这个问题呢?解决方法也比较简单,可以通过引用一个变量来记录要运行的任务,将其从StartAsync方法中解放出来。

public class PrinterHostedService3 : IHostedService, IDisposable { //others ..... private bool _stopping; private Task _backgroundTask; public Task StartAsync(CancellationToken cancellationToken) { Console.WriteLine("Printer3 is starting."); _backgroundTask = BackgroundTask(cancellationToken); return Task.CompletedTask; } private async Task BackgroundTask(CancellationToken cancellationToken) { while (!_stopping) { await Task.Delay(TimeSpan.FromSeconds(_settings.PrinterDelaySecond),cancellationToken); Console.WriteLine("Printer3 is doing background work."); } } public Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("Printer3 is stopping."); _stopping = true; return Task.CompletedTask; } public void Dispose() { Console.WriteLine("Printer3 is disposing."); } }

这样就能让这个任务真正的启动成功了!效果就不放图了。

相对来说,BackgroundService用起来会比较简单,实现核心的ExecuteAsync这个抽象方法就差不多了,出错的概率也会比较低。

IHostBuilder的扩展写法

在注册服务的时候,我们还可以通过编写IHostBuilder的扩展方法来完成。

public static class Extensions { public static IHostBuilder UseHostedService<T>(this IHostBuilder hostBuilder) where T : class, IHostedService, IDisposable { return hostBuilder.ConfigureServices(services => services.AddHostedService<T>()); } public static IHostBuilder UseComsumeRabbitMQ(this IHostBuilder hostBuilder) { return hostBuilder.ConfigureServices(services => services.AddHostedService<ComsumeRabbitMQHostedService>()); } }

使用的时候就可以像下面一样。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdsjpy.html