简体   繁体   English

如何在 ASP.net 内核中手动取消 BackgroundService

[英]How to cancel manually a BackgroundService in ASP.net core

I create a BackgroundService like this:我创建一个这样的BackgroundService:

public class CustomService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        do
        {
            //...

            await Task.Delay(60000, cancellationToken);
        }
        while (!cancellationToken.IsCancellationRequested);
    }
}

How to cancel it manually?如何手动取消?

It's unclear whether you want to cancel all services and maybe the application itself (or at least the host), or just a single service.目前尚不清楚您是要取消所有服务,也可能是应用程序本身(或至少是主机),还是只取消一项服务。

Stopping the application停止应用程序

To cancel the application, inject the IHostApplicationLifetime interface in the class that will force the cancellation and call StopApplication when needed.要取消应用程序,请在 class 中注入IHostApplicationLifetime接口,该接口将强制取消并在需要时调用StopApplication If you want to cancel from inside the background service itself, perhaps because there's nothing else to do, that's where you need to inject.如果您想从后台服务本身内部取消,可能是因为没有其他事情可做,那就是您需要注入的地方。

StopApplication will tell the host the application needs to shut down. StopApplication将告诉主机应用程序需要关闭。 The host will call StopAsync on all hosted services.主机将对所有托管服务调用StopAsync Since you use BackgroundService , the implementation will trigger the cancellationToken passed to ExecuteAsync :由于您使用BackgroundService实现将触发cancellationToken传递给ExecuteAsync

    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        // Stop called without start
        if (_executeTask == null)
        {
            return;
        }

        try
        {
            // Signal cancellation to the executing method
            _stoppingCts.Cancel();
        }
        finally
        {
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executeTask, Task.Delay(Timeout.Infinite, cancellationToken)).ConfigureAwait(false);
        }

    }

You don't have to change your current code at all.您根本不必更改当前代码。 The only concern is that await Task.Delay() leaks timers.唯一需要担心的是await Task.Delay()泄漏计时器。 It would be better to use a Timer explicitly, and dispose it when cancellation is triggered.最好显式使用Timer ,并在触发取消时将其处理掉。

For example, if you want to shut down the application from a controller action:例如,如果您想通过 controller 操作关闭应用程序:

public class MyServiceControllerr:Controller
{
    IHostApplicationLifetime _lifetime;
    public MyServiceController(IHostApplicationLifetime lifeTime)
    {
        _lifeTime=lifeTime;
    }

    [HttpPost]
    public IActionResult Stop()
    {
        _lifeTime.StopApplication();
        return Ok();
    }
}

Stopping the service停止服务

If you want to stop just this one service, you need a way to call its StopAsync method from some other code.如果您只想停止这一项服务,您需要一种从其他代码调用其StopAsync方法的方法。 There are numerous ways to do this.有很多方法可以做到这一点。 One such way is to inject CustomService to the caller and call StopAsync .一种这样的方法是将CustomService注入调用者并调用StopAsync That's not a very good idea though, as it exposes the service and couples the controller/stopping code with the service.但这不是一个好主意,因为它公开了服务并将控制器/停止代码与服务耦合。 Testing this won't be easy either.测试这也不容易。

Another possibility is to create an interface just for the call to StopAsync , eg:另一种可能性是为调用StopAsync创建一个接口,例如:

public interface ICustomServiceStopper
{
    Task StopAsync(CancellationToken token=default);
}

public class CustomService : BackgroundService,ICustomServiceStopper
{
    ...

    Task ICustomServiceStopper.StopAsync(CancellationToken token=default)=>base.StopAsync(token);
    
}

Register the interface as a singleton:将接口注册为 singleton:

services.AddSingleton<ICustomServiceStopper,CustomService>();

and inject ICustomServiceStopper when needed:并在需要时注入ICustomServiceStopper

public class MyServiceControllerr:Controller
{
    ICustomServiceStopper _stopper;
    public MyServiceController(ICustomServiceStopper stopper)
    {
        _stopper=stopper;
    }

    [HttpPost]
    public async Task<IActionResult> Stop()
    {
        await _stopper.StopAsync();
        return Ok();
    }
}

I've checked the BackgroundService source code我检查了BackgroundService 源代码

and it looks like my previous answer was wrong.看来我之前的回答是错误的。

The ExecuteAsync parameter is a token provided by the StartAsync method. ExecuteAsync参数是StartAsync方法提供的令牌。

The BackgroundService token source is cancelled by the StopAsync method. BackgroundService令牌源由StopAsync方法取消。

So to cancel the CustomService async work you have to call the StopAsync method.因此,要取消CustomService异步工作,您必须调用StopAsync方法。 This cancel token provided to the ExecuteAsync method as parameter.此取消令牌作为参数提供给ExecuteAsync方法。

It's late, but simply trigger StopAsync(CancellationToken cancellationToken) method, which is part of BackgroundService interface, it will only stop your current worker, not the whole app:很晚了,但只需触发StopAsync(CancellationToken cancelToken)方法,它是BackgroundService接口的一部分,它只会停止您当前的工作人员,而不是整个应用程序:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    var stopCounter = 10;
    while (!stoppingToken.IsCancellationRequested)
    {
        _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
        await Task.Delay(1000, stoppingToken);
        stopCounter--;
        if (stopCounter < 1)
        {
            StopAsync(stoppingToken);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何手动重启 ASP.net 核心中的 BackgroundService - How to restart manually a BackgroundService in ASP.net core 有没有办法在 Asp.Net core 3.1 中手动启动 BackgroundService - Is there a way to manually start BackgroundService in Asp.Net core 3.1 .NET 5 WindowsService with ASP.NET Core and BackgroundService - .NET 5 WindowsService with ASP.NET Core and BackgroundService 如何在 ASP.NET Core 2.1 中的计时器上运行 BackgroundService - How to run BackgroundService on a timer in ASP.NET Core 2.1 ASP.Net core 3.1中如何启动BackgroundService API - How to start BackgroundService in ASP.Net core 3.1 API 从asp.net core 2.1中的控制器访问BackgroundService - access BackgroundService from controller in asp.net core 2.1 在ASP.NET Core中启动BackgroundService的正确方法 - Correct way to start a BackgroundService in ASP.NET Core 在 ASP.NET Core 中处理 BackgroundService 中的非托管回调 - Handle unmanaged callback in BackgroundService in ASP.NET Core ASP.Net Core BackgroundService被无故取消 - ASP.Net Core BackgroundService is cancelled without reason asp.NET Core timed BackgroundService 不能在 Controller 中使用 StopAsync() 停止 - asp.NET Core timed BackgroundService cannot be stopped in Controller with StopAsync()
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM