Scheduler后台服务中的异步计时器 [英] Async timer in Scheduler Background Service

查看:108
本文介绍了Scheduler后台服务中的异步计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用.Net-Core编写托管服务,该服务基于计时器在后台运行作业。

I'm writing a hosted service in .Net-Core which runs a job in the background based off of a timer.

当前,我必须编写同步运行的代码像这样:

Currently I have to code running synchronously like so:

public override Task StartAsync(CancellationToken cancellationToken)
{
    this._logger.LogInformation("Timed Background Service is starting.");

    this._timer = new Timer(ExecuteTask, null, TimeSpan.Zero,
        TimeSpan.FromSeconds(30));

    return Task.CompletedTask;
}

private void ExecuteTask(object state)
{
    this._logger.LogInformation("Timed Background Service is working.");
    using (var scope = _serviceProvider.CreateScope())
    {
        var coinbaseService = scope.ServiceProvider.GetRequiredService<CoinbaseService>();
        coinbaseService.FinalizeMeeting();
    }
}

我想在计时器上运行此Async但是我不想用火跑异步并忘记,因为这可能会导致代码中出现争用情况。
例如(订阅 timer.Elapsed 事件)

I'd like to run this Async on the timer but I don't want to run async using fire and forget because my it could cause race conditions in my code. e.g( subscribing to the timer.Elapsed event)

有没有一种方法可以利用异步定时执行的程序代码,而无需执行操作并忘记执行

Is there a way I can leverage asynchronous code on a timed schedule without executing fire and forget

推荐答案

async 是不占用主线程。但这已经是一个后台线程,因此它并不重要-除非它是ASP.NET Core应用程序。这是唯一重要的时间,因为线程池有限,耗尽它意味着无法再处理更多请求。

The whole purpose of async is to not hold up the primary threads. But this is a background thread already, so it doesn't really matter - unless it's an ASP.NET Core application. That's the only time it would matter since there is a limited thread pool and exhausting it means that no more requests can be served.

如果您真的想运行它 async ,只需将其设为 async

If you really want to run it async, just make it async:

private async void ExecuteTask(object state)
{
    //await stuff here
}

是的,我知道您说您不想解雇,但是事件确实就是这样:它们解雇了。因此,您的 ExecuteTask 方法将被调用,无论(1)仍在运行还是(2)是否失败,都不会在意(或检查)。 无论是否运行此 async ,都是如此。

Yes, I know you say you don't want to "fire and forget", but events really are just that: they're fire and forget. So your ExecuteTask method will be called and nothing will care (or check) if it's (1) still running or (2) if it failed. That is true whether you run this async or not.

您可以减轻故障通过将所有 ExecuteTask 方法包装在 try / catch 阻止并确保将其记录在某处,以便您知道发生了什么。

You can mitigate failures by just wrapping everything your ExecuteTask method in a try/catch block and make sure it's logged somewhere so you know what happened.

另一个问题是知道它是否仍在运行(即使您正在重新运行异步)。

The other issue is knowing if it's still running (which, again, is a problem even if you're not running async). There is a way to mitigate that too:

private Task doWorkTask;

private void ExecuteTask(object state)
{
    doWorkTask = DoWork();
}

private async Task DoWork()
{
    //await stuff here
}

在这种情况下,您的计时器只是开始执行任务。但是不同之处在于,您引用的是 Task 。这样,您就可以在代码中的其他任何地方检查 Task 的状态。例如,如果要验证是否完成,可以查看 doWorkTask.IsCompleted doWorkTask.Status

In this case, your timer just starts the task. But the difference is that you're keeping a reference to the Task. This would let you check on the status of the Task anywhere else in your code. For example, if you want to verify whether it's done, you can look at doWorkTask.IsCompleted or doWorkTask.Status.

此外,当应用程序关闭时,您可以使用:

Additionally, when your application shuts down, you can use:

await doWorkTask;

确保在关闭应用程序之前任务已完成。否则,该线程将被杀死,可能会使事物处于不一致状态。请注意,如果 DoWork()中发生未处理的异常,则使用 await doWorkTask 会引发异常。

to make sure the task has completed before closing your application. Otherwise, the thread would just be killed, possibly leaving things in an inconsistent state. Just be aware that using await doWorkTask will throw an exception if an unhandled exception happened in DoWork().

在开始下一个任务之前验证上一个任务是否已完成也是一个好主意。

It's also probably a good idea to verify if the previous task has completed before starting the next one.

这篇关于Scheduler后台服务中的异步计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆