【问题标题】:Mysterious Behavior of .NET Core Background Task.NET Core 后台任务的神秘行为
【发布时间】:2019-01-24 15:53:09
【问题描述】:

我的第一个问题是微软的这篇文章是否适用于其他程序员:https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/

解释了如何使用后台服务。我有一个程序,它有一个 WEB API,数据输入被插入到数据库中。如果数据库中有新数据,我的后台作业应该每分钟显示一次,并且应该处理对其他 web 服务的一些请求。

我的问题是,有时它会触发两次或作业没有运行。每次后台服务执行时间戳时,我都会打印到控制台。过了一会儿,就再也没有打印出来了。

这是我的示例代码。我的代码或配置有问题吗?

First Code-Sample 是 ConfigureService 方法中 Startup-Class 的代码:

//Adding Background Task Class to Hosted Services in Startup-Class and Method ConfigureServices
services.AddHostedService<JsonDataCreator>();

这里是保存我的后台服务逻辑的类的实现:

 /// <summary>
/// Background Service which creates the JSON Files for the machine
/// </summary>
public class JsonDataCreator : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="logger">Logger functionallity</param>
    public JsonDataCreator(ILogger<JsonDataCreator> logger)
    {
        _logger = logger;
    }


    /// <summary>
    /// Task which is executed Asynchronous
    /// </summary>
    /// <param name="cancellationToken">Cancellation token for stopping the Task</param>
    /// <returns>Task Completed</returns>
    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting");
        Console.WriteLine("Timed Background Service is starting");
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
        return Task.CompletedTask;
    }

    /// <summary>
    /// Logical Request to Webservice + Database and creation of JSON Files
    /// </summary>
    /// <param name="state"></param>
    private void DoWork(object state)
    {
        try
        {
            Console.WriteLine("Begin new Round of Background-Work" +                                     DateTime.Now.ToShortTimeString());
            //THERE IS SOME LOGIC INSIDE WHICH CALLS SOME WEBSERVICE
        }catch(Exception ex)
        {

            Console.WriteLine(ex.Message);
        }                 
    }

    /// <summary>
    /// Stops the Task
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns>Task Completed</returns>
    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping");
        Console.WriteLine("Timed Background Service is stopping");
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    /// <summary>
    /// Disposes the Task
    /// </summary>
    public void Dispose()
    {
        _timer?.Dispose();
    }
}

【问题讨论】:

  • 这里没有任何内容表明该任务将运行两次。当它停止运行时,您是否在日志中看到调用 StopAsync 的等效消息?另外,我会销毁StopAsync 中的计时器,而不是更改时间间隔。
  • @DavidG 神秘的东西是,后台任务是确定的,不再执行,但 stopasync 也没有被触发。所以我不知道问题出在哪里。后台任务通常是为这样的解决方案设计的吗?
  • @stuartd 没错。 StopAsync 等方法由接口命名。目前我不需要任何异步功能
  • 你为什么不使用一个无休止的时间并删除计时器?它工作得很好,并且避免了线程(定时器)和任务的混合。
  • @MarioVernari 我想在下一个执行周期开始前等待一分钟

标签: c# .net-core backgroundworker


【解决方案1】:

我通过使用提供的无限循环解决方案解决了这个问题。从现在开始,没有关于超时和取消任务的神秘行为。

解决方案如下所示:

     /// <summary>
/// Background Service which creates the JSON Files for the machine
/// </summary>
public class JsonDataCreator : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="logger">Logger functionallity</param>
    public JsonDataCreator(ILogger<JsonDataCreator> logger)
    {
        _logger = logger;
    }


    /// <summary>
    /// Task which is executed Asynchronous
    /// </summary>
    /// <param name="cancellationToken">Cancellation token for stopping the Task</param>
    /// <returns>Task Completed</returns>
    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting");
        while(true){
            //Do the business logic
            //Wait the time you want
        }
        return Task.CompletedTask;
    }



    /// <summary>
    /// Stops the Task
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns>Task Completed</returns>
    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping");
        Console.WriteLine("Timed Background Service is stopping");
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    /// <summary>
    /// Disposes the Task
    /// </summary>
    public void Dispose()
    {
        _timer?.Dispose();
    }
}

希望对你也有帮助。

【讨论】:

  • 所以你永远不能停止服务? xD 我不认为这很聪明
  • @Ramomex1 它在 docker 容器中构建 - 所以我可以停止容器并完成工作。
猜你喜欢
  • 2023-03-20
  • 2021-02-14
  • 2020-11-20
  • 1970-01-01
  • 2022-01-07
  • 2023-03-31
  • 1970-01-01
  • 2017-10-17
  • 2022-01-13
相关资源
最近更新 更多