[英]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.