重写 IHostedService 以在所有任务完成后停止 [英] rewrite an IHostedService to stop after all tasks finished

查看:25
本文介绍了重写 IHostedService 以在所有任务完成后停止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an application that normally should be a simple console application to be programmed as a scheduled task from time to time called by the windows task scheduler.

程序应该在两个数据库上启动一些更新,每个数据库一个服务.假设 ContosoDatabase 应该由 ContosoService 更新.

The program should launch some updates on two databases, one service per one database. Say ContosoDatabase should be updated by the ContosoService.

最后,它被编写为 .NET Core 应用程序,使用可能不是最佳选择IHostedServices 作为服务的基础,如下所示:

Finally it was written as an .NET Core app using, and maybe is not the best choice, the IHostedServices as base for the service, like this:

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;
    }
}

我像这样从 main 调用它:

and I call it from main like this:

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>()));
        }
    });

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

Now, the problem, is surely, that the application will not stop once all updates finished.

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

Is there a way to quickly rewrite the application in order to make it stop after the second service finishes its tasks?

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

public static void Main(string[] args) {
    try {
        CreateHostBuilder(filteredArgs.ToArray()).Build().Run();                
    }
    catch (Exception ex) {
        //Log....
    }

    Environment.Exit(0); // here
}

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

but it does not seem to help: the application is still running after all task are completed.

推荐答案

HostedServices 是后台服务.反之亦然:它们可以对应用程序的启动和停止事件做出反应,以便它们可以优雅地结束.它们并不意味着在完成后停止您的主应用程序,它们可能与应用程序一样长.

HostedServices are background services. It's the other way around: they can react to application start and stop events, so that they can end gracefully. They are not meant to stop your main application when finished, they potentially live as long as the application does.

我想说,简单的任务和等待所有任务会更好地为您服务.或者在您的后台作业完成其工作并在 main 中处理它们时发送一些事件.

I'd say you will be better served with simple Tasks and awaiting all of them. Or send some events when your background jobs finishes its work and handle them in main.

无论您选择什么触发器,您都可以通过注入 IHostApplicationLifetime 并在其上调用 StopApplication() 方法来停止 .net 应用程序.在早期版本中,它只是 IApplicationLifetime.

Whatever trigger you may choose you can stop .net app by injecting IHostApplicationLifetime and calling StopApplication() method on it. In earlier versions it's just IApplicationLifetime.

这篇关于重写 IHostedService 以在所有任务完成后停止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆