【发布时间】:2021-02-05 12:54:57
【问题描述】:
尊敬的女士们,先生们,我最近在 .Net Core 3.1 中第一次使用 Worker 服务,而在一般的 Windows 服务中只进行了第二次(第一次是在 .Net Framework 中制作的,直到今天都可以正常工作) .如果有人可以阐明我将提供的示例中缺少的内容,那就太好了。
所以,为了简单起见,我的问题是: 我假设长时间(永远)运行的 Worker 服务在一天中的任意时间意外停止工作,但在服务管理器中仍显示为“正在运行”(这可能是 Windows 处理服务的方式)。不一定要每天都这样,但它会时不时停止工作,直到我手动停止它然后在服务管理器中重新启动它。
我也有stumbled upon this question,它似乎可以解决我的问题,但即使在将我的所有服务代码块完全包装在 try-catch 中之后,即使在顶层,我仍然没有在我的 Log 表中注册任何内容,或者如果我的数据库连接失败,即使在我设置写入的文件中。服务似乎只是停止调用 ExecuteAsync() 方法。
好的,这是我的代码的逻辑结构,我已经排除了实现,我只是展示在调用 DoWork 之前会发生什么:
public class Worker : BackgroundService
{
private readonly IConfiguration _configuration;
public Worker(IConfiguration configuration)
{
_configuration = configuration;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
return base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (true)
{
try //paranoid try-catch
{
await DoWork();
await Task.Delay(TimeSpan.FromSeconds(45), stoppingToken);
}
catch (Exception e)
{
await Log(e, customMessage: "Proccess failed at top level.");
}
}
}
catch (Exception e)
{
await Log(e, customMessage: "Proccess failed at topmost level.");
}
}
private async Task DoWork()
{
try
{
}
catch (Exception e)
{
await Log(e);
}
}
public async Task Log(Exception e, string user = null, string emailID = null, string customMessage = null)
{
}
}
如您所见,我没有处理取消,就像我上面链接的问题一样。现在我考虑一下,也许我应该这样做,而某些事情是无意中发送了取消?我没有这样做的原因是因为我不确定哪些事件确切地表明了取消。只有手动停止服务,或者其他什么可能?如果是发送的取消导致我的服务停止工作,它不应该也停止我的服务运行吗?
顺便说一句,我刚刚在虚拟服务上测试了取消,它使用while(true) 实现了我的逻辑,它捕获了停止异常,即使它有点尴尬,因为它捕获它并在停止之前多次记录它,所以我认为它可能不是导致我的 DoWork 不触发的取消令牌。
【问题讨论】:
-
您检查过Stephen C.'s answer 中的改进了吗?考虑到 stopToken 是其中之一,但我专门针对他指的是停止应用程序主机的部分。并在处理异常时记下令牌的状态。
-
可能是例如死锁。然后对于 Windows,您的服务确实仍在运行,而实际上它被卡在某个地方并且没有做任何有用的事情(并且没有例外)。
-
如果您的日志记录功能失败怎么办?是写SQL还是什么?如果出现短暂的网络错误,或者连续出现两个 SQL 死锁,那么它将停止
-
@Fildor 尽管在我看来我确实犯了一个错误并将托管服务视为应用程序,但我认为这不会让我担心,因为我希望我的 BackgroundService 永远不会退出。但是,我仍然认为添加实施该附件在逻辑上是正确的。我认为 Evk 更符合可能发生的情况,因为我的服务严重依赖异步。
-
我会首先确保您在每次此类呼叫时都有超时。因为如果您通过 TCP 连接(即 http,通常是数据库和许多其他调用)发送一些请求并且没有超时 (0),并且连接意外中断 - 您将永远等待回复。因此,对于任何此类操作,都应该有一个合理的超时设置(通常与数据库一起使用的 api、http 调用等都提供了一种设置方法)。如果您使用任何类型的锁(
lock等,或异步类似物),那么当然也要检查它们。
标签: c# .net-core async-await worker