![](/img/trans.png)
[英]How can I manually cancel a .NET core IHostedService background task?
[英].Net core IHostedService Background task exception will not terminate application
我有一個程序需要在 IHostedService 后台任務遇到某種情況時終止。 我希望通過在后台任務中拋出一個異常來實現這一點,該異常將被踢到主函數。 然后我可以觸發取消令牌來終止其他后台任務。 我的問題是,當我拋出異常時,它會終止任務,僅此而已。 其他一切都在繼續運行。 有沒有辦法做到這一點,或者有更好的方法來做我想做的事情? 是否有另一種方法可以讓后台任務觸發通用的 CancellationToken?
我在下面的代碼中包含了我的問題的簡化版本。 如果我注釋掉await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
行,異常做了我想要的,我可以觸發 CancellationToken。 當它就位時,任務會停止,但程序不會。
注意:在我更混亂的代碼中,我有更多的 IHostedServices 正在運行,這就是為什么我試圖觸發cancelSource.Cancel()
public class Program
{
public static async Task Main(string[] args)
{
using (var cancelSource = new CancellationTokenSource())
{
try
{
await new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<TestService>();
})
.Build()
.RunAsync(cancelSource.Token);
}
catch (Exception E)
{
cancelSource.Cancel();
}
}
}
}
public class TestService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
Console.WriteLine("loop 1");
throw new ApplicationException("OOPS!!");
}
}
}
使用await
運算符注釋ExecuteAsync
方法中的唯一行會使您的代碼同步運行。 如果我們查看BackgroundService.StartAsync
的來源,我們可以看到它檢查_executingTask.IsCompleted
並返回包含異常的任務,以防我們在ExecuteAsync
方法中沒有任何 await,否則它將返回Task.CompletedTask
和您將無法從Main
方法中的ExecuteAsync
捕獲此異常。
您可以使用ApplicationLifetime管理您的服務,該服務可以注入所有后台服務,例如您可以在ExecuteMethod
捕獲異常並調用ApplicationLifetime.StopApplication
例子:
static async Task Main(string[] args)
{
await new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<TestService>();
services.AddHostedService<TestService2>();
})
.Build()
.RunAsync();
Console.WriteLine("App stoped");
}
服務1
public class TestService : BackgroundService
{
private readonly IApplicationLifetime _applicationLifetime;
public TestService(IApplicationLifetime applicationLifetime)
{
_applicationLifetime = applicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!_applicationLifetime.ApplicationStopping.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1), _applicationLifetime.ApplicationStopping);
Console.WriteLine("running service 1");
throw new ApplicationException("OOPS!!");
}
}
catch (ApplicationException)
{
_applicationLifetime.StopApplication();
}
}
}
服務2
public class TestService2 : BackgroundService
{
private readonly IApplicationLifetime _applicationLifetime;
public TestService2(IApplicationLifetime applicationLifetime)
{
_applicationLifetime = applicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!_applicationLifetime.ApplicationStopping.IsCancellationRequested)
{
await Task.Delay(100, _applicationLifetime.ApplicationStopping);
Console.WriteLine("running service 2");
}
}
catch (ApplicationException)
{
_applicationLifetime.StopApplication();
}
}
}
輸出:
running service 2
running service 2
running service 1
App stoped
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.