后台服务中的 Task.Run 意外停止工作
Posted
技术标签:
【中文标题】后台服务中的 Task.Run 意外停止工作【英文标题】:Task.Run inside backgroundservice unexpectedly stops working 【发布时间】:2020-12-14 00:16:57 【问题描述】:我在后台服务中使用 Task.Run。我有后台服务,负责特定系统的登录和发送心跳。
public class TestBGService : IHostedService
private readonly ITestService _testService;
private bool MustLogOn get; set; = true;
private string id get; set;
public TestBGService(ITestService testService)
_testService = testService;
public async Task StartAsync(CancellationToken cancellationToken)
while (!cancellationToken.IsCancellationRequested)
Log.Information("TestBGService starts Initialize");
await Initialize();
public Task StopAsync(CancellationToken cancellationToken)
return Task.CompletedTask;
private async Task Initialize()
try
if (MustLogOn)
Log.Information("TestBGService ExecuteAsync trying to LogOnAsync");
id = await _testService.LogOnAsync();
if (!string.IsNullOrEmpty(id))
Log.Information($"new id equals to id");
MustLogOn = false;
_ = Task.Run(async () =>
while (true)
bool res = await SendHeartBeat(id);
Log.Information($"res from SendHeartBeat res");
if (!res)
break;
await Task.Delay(10000);
);
await _testService.StartProcessAsync(id);
catch (Exception ex)
Log.Error($"TestBGService ExecuteAsync throws ex.ToString()");
private async Task<bool> SendHeartBeat(string id)
bool isSuccess = true;
try
Log.Information("TestBGService sending heartbeat at " + DateTime.Now);
var response = new HeartBeatResponseModel();
response = await _testService.SendHeartBeatAsync(id);
Log.Information("TestBGService heartbeat response equals to " + response.IsSuccessful);
if (!response.IsSuccessful)
MustLogOn = true;
isSuccess = response.IsSuccessful;
catch (Exception ex)
Log.Error(ex, "TestBGService SendHeartBeat throws");
isSuccess = false;
MustLogOn = true;
return isSuccess;
Initialize 方法尝试LogOn 到系统,在成功的情况下,它需要启动SendHeartBeat。 SendHeartBeat 方法负责获取成功或失败。如果成功,我将 MustLogon 的值更改为 false 并每 10 秒发送一次 SendHeartBeat。 SendHeartBeat 的并行我需要调用_testService.StartProcessAsync
从流中获取数据。不知何故它停止工作并再次启动 LogOn 但我需要它直到它返回 false 它应该工作并且 SendHeartBeat 需要每 10 秒完成一次但不幸的是,它在 bool res = true
的情况下停止工作并且此刻它不会抛出任何例外。有什么建议吗?
【问题讨论】:
看看这个例子:docs.microsoft.com/en-us/aspnet/core/fundamentals/host/… 并尝试相应地修改您的代码。你不应该永远在 StartAsync 方法中徘徊。 Fildor,当我发送cancellationToken时它停止 是的,因为这是垃圾(抱歉)。请查看定时服务应该如何工作(请参阅第一条评论中的链接)。在 Timer Callback 中: 1. 如果需要,请登录, 2. SendHeartBeat。完毕。不要从任务中开始任务... 或者您可以从提供的链接@Fildor 中快速使用BackgroundService
,将您的“Initialize
”逻辑移动到ExecuteAsync
(并删除Task.Run
这里有什么意义?)。
没有什么能阻止你这样做。
【参考方案1】:
这是我在BackgroundService base class 的链接之后想出的,并“插入”您所需的功能:(当然,未经测试)
public class TestBGService : BackGroundService
// I guess you are using different logging
private readonly ILogger<TestBGService> _logger;
// Your service to send Heartbeats to
private readonly ITestService _testService;
// If id is null, we need to login.
private string _id = null;
public TestBGService (ILogger<TestBGService> logger, ITestService testService)
_logger = logger;
_testService = testService ?? throw new ArgumentNullException(nameof(testService));
public Task StartAsync(CancellationToken stoppingToken)
_logger.LogInformation("TestBGService running.");
return Task.CompletedTask;
// This will be triggered by the runtime.
private async Task ExecuteAsync (System.Threading.CancellationToken stoppingToken)
while( !stoppingToken.CancellationRequested )
try
if( string.IsNullOrEmpty(_id) )
// _id is null => perform login
_id = await _testService.LogOnAsync(); // perhaps pass stoppingToken?
bool res = await SendHeartBeat(id); // again: consider passing stoppingToken
if( !res ) _id = null; // Heartbeat unsuccessful: login next time
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
catch(Exception ex) // You should actually catch more specific exceptions.
// TODO log Exception
_id = null; // Reset id, so we login next time.
private async Task<bool> SendHeartBeat(string id)
// Don't even try if login was unsuccessful.
if ( string.IsNullOrEmpty(id) ) return false;
_logger.LogInformation("TestBGService sending heartbeat at 0" , DateTime.Now);
var response = await _testService.SendHeartBeatAsync(id);
_logger.LogInformation("TestBGService heartbeat response 0successful", response.IsSuccessful ? "" : "un");
return response.IsSuccessful;
public Task StopAsync(CancellationToken stoppingToken)
_logger.LogInformation("TestBGService is stopping.");
// TODO maybe explicit logout?
return Task.CompletedTask;
【讨论】:
以上是关于后台服务中的 Task.Run 意外停止工作的主要内容,如果未能解决你的问题,请参考以下文章