.net core 重写IHostedService以在所有任务完成后停止
我有一个应用程序,通常应该是一个简单的控制台应用程序,可以作为windows任务调度器不时调用的计划任务进行编程 该程序应该在两个数据库上启动一些更新,每个数据库一个服务。假设contosososervice应该更新ContosoDatabase 最后,它被编写成一个.NET核心应用程序,使用IHostedServices作为服务的基础,这可能不是最好的选择,如下所示:.net core 重写IHostedService以在所有任务完成后停止,.net-core,background-process,.net-5,asp.net-core-hosted-services,ihostedservice,.net Core,Background Process,.net 5,Asp.net Core Hosted Services,Ihostedservice,我有一个应用程序,通常应该是一个简单的控制台应用程序,可以作为windows任务调度器不时调用的计划任务进行编程 该程序应该在两个数据库上启动一些更新,每个数据库一个服务。假设contosososervice应该更新ContosoDatabase 最后,它被编写成一个.NET核心应用程序,使用IHostedServices作为服务的基础,这可能不是最好的选择,如下所示: public class ContosoService : IHostedService { private read
public class ContosoService : IHostedService {
private readonly ILogger<ContosoService> _log;
private readonly IContosoRepository _repository;
private Task executingTask;
public ContosoService(
ILogger<ContosoService> log,
IContosoRepository repository,
string mode) {
_log = log;
_repository = repository;
}
public Task StartAsync(CancellationToken cancellationToken) {
_log.LogInformation(">>> {serviceName} started <<<", nameof(ContosoService));
executingTask = ExcecuteAsync(cancellationToken);
// If the task is completed then return it,
// this should bubble cancellation and failure to the caller
if (executingTask.IsCompleted)
return executingTask;
// Otherwise it's running
// >> don't want it to run!
// >> it should end after all task finished!
return Task.CompletedTask;
}
private async Task<bool> ExcecuteAsync(CancellationToken cancellationToken) {
var myUsers = _repository.GetMyUsers();
if (myUsers == null || myUsers.Count() == 0) {
_log.LogWarning("{serviceName} has any entry to process, will stop", this.GetType().Name);
return false;
}
else {
// on mets à jour la liste des employés Agresso obtenue
await _repository.UpdateUsersAsync(myUsers);
}
_log.LogInformation(">>> {serviceName} finished its tasks <<<", nameof(ContosoService));
return true;
}
public Task StopAsync(CancellationToken cancellationToken) {
_log.LogInformation(">>> {serviceName} stopped <<<", nameof(ContosoService));
return Task.CompletedTask;
}
}
public static void Main(string[] args)
{
try {
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex) {
Log.Fatal(ex, ">>> the application could not start <<<");
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host
.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => {
var config = hostContext.Configuration;
if (args.Contains("Alonso")) {
services
.AddHostedService(provider =>
new AlonsoService(
provider.GetService<ILogger<AlonsoService>>(),
provider.GetService<IAlonsoRepository>()));
}
// if there also Cedig in the list, they can be run in parallel
if (args.Contains("Contoso")) {
services
.AddHostedService(provider =>
new ContosoService(
provider.GetService<ILogger<ContosoService>>(),
provider.GetService<IContosoRepository>()));
}
});
但这似乎没有帮助:在所有任务完成后,应用程序仍在运行。托管服务是后台服务。另一种方法是:它们可以对应用程序的启动和停止事件做出反应,从而可以优雅地结束。它们并不意味着在完成时停止主应用程序,它们可能和应用程序一样长 我想说,简单的任务和等待所有的任务会让你得到更好的服务。或者在后台作业完成工作后发送一些事件,并在main中处理它们
无论您选择什么触发器,都可以通过注入IHostApplicationLifetime并对其调用StopApplication方法来停止.net应用程序。在早期版本中,它只是IApplicationLifetime。在主机关闭之前,查看方法运行不会停止。似乎StopAsync没有停止服务。so Environment.Exit0;从未联系过。可能用于强制结束主机,或注入Environment.Exit0;在ContosoService类中,如果可能的话,即使不是最优的。根据@Maxim的建议,我通过注入IHostApplicationLifetime和lastService布尔值发现了这个肮脏但有效的解决方法:
我如何从我的服务向主应用发送消息以停止它?或者,更确切地说,我想在所有服务完成后停止应用,如何执行?IHostApplicationLifetime完成了任务,我刚刚从上一个执行服务spasibo bol'shoe中删除了应用;使用CancellationTocker强制停止主机,这将非常好。。。现在想知道如何从应用程序内部执行此操作…请查看我自己的答案,谢谢并感谢@maxim:!我知道您解决了这个问题,但我注意到StopAsync没有在任何地方被调用。我想如果它放在同一个地方而不是_hostApplicationLifetime.stopplication;它将产生相同的结果。应用程序或主机在尝试停止应用程序时似乎调用了StopAsync。我有来自StopAsync的日志,在StopApplication调用之后传递感谢您提供的信息。很高兴你的问题解决了。
public static void Main(string[] args) {
try {
CreateHostBuilder(filteredArgs.ToArray()).Build().Run();
}
catch (Exception ex) {
//Log....
}
Environment.Exit(0); // here
}
public ConsosoService(
IHostApplicationLifetime hostApplicationLifetime,
// ...
bool lastService)
{ ... }
public async Task StartAsync(CancellationToken cancellationToken)
{
// do the job
if (_lastService)
_hostApplicationLifetime.StopApplication();
// stops the application and cancel/stops other services as well
}