重写 IHostedService 以在所有任务完成后停止

Ser*_*rge 4 background-process .net-core asp.net-core-hosted-services .net-5 ihostedservice

我有一个应用程序,通常应该是一个简单的控制台应用程序,可以编程为 Windows 任务计划程序不时调用的计划任务。

\n

该程序应该在两个数据库上启动一些更新,每个数据库一项服务。说ContosoDatabase应该更新ContosoService

\n

最后,它被编写为一个 .NET Core 应用程序,使用s作为服务的基础,这也许不是最好的选择,如下所示:IHostedService

\n
public class ContosoService : IHostedService {\n    private readonly ILogger<ContosoService> _log;\n    private readonly IContosoRepository _repository;\n    \n    private Task executingTask;\n\n    public ContosoService(\n        ILogger<ContosoService> log,\n        IContosoRepository repository,\n        string mode) {\n        _log = log;\n        _repository = repository;\n    }\n\n    public Task StartAsync(CancellationToken cancellationToken) {\n        _log.LogInformation(">>> {serviceName} started <<<", nameof(ContosoService));\n        executingTask = ExcecuteAsync(cancellationToken);\n\n        // If the task is completed then return it, \n        // this should bubble cancellation and failure to the caller\n        if (executingTask.IsCompleted)\n            return executingTask;\n\n        // Otherwise it's running\n        // >> don't want it to run!\n        // >> it should end after all task finished!\n        return Task.CompletedTask;\n    }\n\n    private async Task<bool> ExcecuteAsync(CancellationToken cancellationToken) {\n        var myUsers = _repository.GetMyUsers();\n\n        if (myUsers == null || myUsers.Count() == 0) {\n            _log.LogWarning("{serviceName} has any entry to process, will stop", this.GetType().Name);\n            return false;\n        }\n        else {\n            // on mets \xc3\xa0 jour la liste des employ\xc3\xa9s Agresso obtenue\n            await _repository.UpdateUsersAsync(myUsers);\n        }\n\n        _log.LogInformation(">>> {serviceName} finished its tasks <<<", nameof(ContosoService));\n        return true;\n    }\n\n    public Task StopAsync(CancellationToken cancellationToken) {\n        _log.LogInformation(">>> {serviceName} stopped <<<", nameof(ContosoService));\n        return Task.CompletedTask;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我从 main 中这样称呼它:

\n
public static void Main(string[] args)\n{\n    try {\n        CreateHostBuilder(args).Build().Run();\n    }\n    catch (Exception ex) {\n        Log.Fatal(ex, ">>> the application could not start <<<");\n    }\n}\n\npublic static IHostBuilder CreateHostBuilder(string[] args) =>\n    Host\n    .CreateDefaultBuilder(args)\n    .ConfigureServices((hostContext, services) => {\n        var config = hostContext.Configuration;\n        \n        if (args.Contains("Alonso")) {\n            services\n            .AddHostedService(provider =>\n                new AlonsoService(\n                    provider.GetService<ILogger<AlonsoService>>(),\n                    provider.GetService<IAlonsoRepository>()));\n        }\n\n        // if there also Cedig in the list, they can be run in parallel\n        if (args.Contains("Contoso")) {\n            services\n            .AddHostedService(provider =>\n                new ContosoService(\n                    provider.GetService<ILogger<ContosoService>>(),\n                    provider.GetService<IContosoRepository>()));\n        }\n    });\n
Run Code Online (Sandbox Code Playgroud)\n

现在的问题肯定是,一旦所有更新完成,应用程序就不会停止。

\n

有没有办法快速重写应用程序,使其在第二个服务完成其任务后停止?

\n

我试图把它放在Environment.Exit(0);最后

\n
public static void Main(string[] args) {\n    try {\n        CreateHostBuilder(filteredArgs.ToArray()).Build().Run();                \n    }\n    catch (Exception ex) {\n        //Log....\n    }\n\n    Environment.Exit(0); // here\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但它似乎没有帮助:所有任务完成后应用程序仍在运行。

\n

Ser*_*rge 5

按照@Maxim的建议,我发现了这个肮脏但有效的解决方法,通过注入IHostApplicationLifetimelastService布尔值:

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
}
Run Code Online (Sandbox Code Playgroud)