工人服务部神秘地停止工作

时间:2020-10-22 13:32:49

标签: c# .net-core async-await worker

我的先生们,先生们,最近我第一次使用.Net Core 3.1中的Worker服务,而第二次通常使用Windows服务(第一个是.Net Framework中的产品,并且到目前为止运行良好) 。如果有人可以阐明我将在示例中提供的内容,那将很棒。

因此,为了简单起见,我的问题是: 我所谓的长期(永远)运行的Worker服务意外地在一天中的任意时间停止工作,但在服务管理器中仍显示为“正在运行”(这可能是Windows处理服务的方式)。它不一定必须每天都在运行,但是它有时会停止工作,直到我手动停止它,然后在Service Manager中重新启动它。

我也有stumbled upon this question,这似乎可以解决我的问题,但是即使将我所有服务的代码块完全包装在try-catch中,即使在顶层,我的日志表中也仍然没有注册任何东西,甚至在我设置为如果数据库连接失败时要写入的文件中。服务似乎只是停止调用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无法启动的取消令牌。

Publish settings (I'd installed it on Windows Server 2012 R2 Standard)

2 个答案:

答案 0 :(得分:0)

好,我已经解决了。参见下面的评论。

猜测,导致死锁的原因可能是通过相同连接从不同线程到数据库的并发调用过多。
并不是我知道那是的原因(,我仍然不知道,只能猜测为什么会这样,所以如果有人能弄清为什么会这样,为什么不打电话,请排队),但是当我尝试修复它时,这似乎是一个不错的起点。

我所做的只是将可能的并发调用限制为1:

  1. 课程级别上实例化SemaphoreSlim:
    private static SemaphoreSlim Semaphore = new SemaphoreSlim(1);
  2. 在调用之后的final块中,在我的数据库调用每个之前插入SemaphoreSlim.WaitAsync,并将其各自的SemaphoreSlim.Release插入:
try
{
    await Semaphore.WaitAsync();
    var id = await sqlCommand.ExecuteScalarAsync().ToString();
}
finally
{
    Semaphore.Release();
}

我以为这会降低性能,但令我惊喜的是,我感觉没有明显的差异。

此外,我很想将Semaphore的初始计数设置为1个以上的线程,但是我发现如果许多线程都发生了死锁,那么可能会发生2-10个线程。也许有人对这个数字了解更多吗?是处理器相关,SQL相关还是C#相关?

答案 1 :(得分:0)

你有没有实现一个dispose方法在完成DoWork方法后关闭数据库连接?我在使用 worker 服务时遇到了死锁问题,并意识到数据库连接没有被释放。实现一个dispose方法后,对我来说就解决了问题。

相关问题