.NET Core Console应用程序

时间:2017-04-04 00:37:56

标签: c# .net multithreading .net-core

简短版本是 - 我如何(2017年发布.NET Core 1.1)在.NET Core 控制台应用中使用依赖注入运行重复任务?< / p>

长篇故事和代码片段。

目标

我有4个(并且会有更多)服务,每个服务都说一个执行某个独立任务并与数据库交互的方法。具体来说,我有一个服务从数据库中删除旧数据,一个服务“缓存”数据(在数据库中运行数据并将聚合结果存储在其他表中),一个生成随机数据等等...这个想法是以不同的间隔运行这些任务,例如每20秒或每天运行一次。

当前的脏实现

我有一项服务,每个任务都有一个while(true)循环,用DI生成服务,运行任务,Thread.Sleep(interval),检查退出条件(全班标志)和continue/break 。大多数方法都是async

当前问题

首先,我知道while(true)Thread.Sleep(interval)是一个巨大的黑客(技术债务)。其次,我有内存泄漏,我觉得我产生/处置服务的方式与它有关。最后,代码遇到随机错误,吞下所有异常。我无法以任何已知的方式捕捉它们。

我想要的解决方案

我想达到目标,但如果可能的话

  • 避免使用像Hangfire和Quartz这样的大型框架。我觉得我不需要他们所能做到的一小部分。
  • 保持app一个控制台应用程序。虽然这是ASP项目的“帮助者”,但我希望它是一个控制台应用程序,并且能够像dotnet daemons.dll一样运行它,并且它会无限期地完成它,直到我Ctrl+C它为止。它也不应该在内存和CPU /线程消耗中增长。只要它是一个稳定的数字,它就可以吃掉相当数量的RAM。
  • 使用Microsoft DI。这就是我所有服务的构建方式。
  • 保留我的服务async。我可以在不同的场景中重复使用它们,包括单元测试。

代码段

我如何运行重复任务的示例:

private async Task RunCacheServiceAsync()
{
    // Make sure the service is set to run.
    _status[ServiceManagerServices.Cache] = true;

    _logger.LogInformation(LoggingEvents.ServiceManager.AsInt(), "Cache service started.");

    while (true)
    {
        var metrics = await _serviceProvider
            .GetRequiredService<DataContext>()
            .Metrics
            .ToListAsync();

        // Run the tasks
        var tasks = metrics
            .Select(
                (metric) =>
                Task.Factory.StartNew(async () =>
                {
                    await _serviceProvider
                        .GetRequiredService<ICacheService>()
                        .CacheMetric(metric);
                })
            );

        // Wait completion of all tasks
        await Task.WhenAll(tasks.ToArray());

        // Wait
        Thread.Sleep(_intervals[ServiceManagerServices.Cache]);

        // Check exit condition
        if (!_status[ServiceManagerServices.Cache])
        {
            break;
        }
    }
}

我需要定期执行的任务示例:

public async Task CleanDataPointsAsync()
{
    var toTimestamp = DateTime.Now - _maxAge;

    // remove data points of all types
    _context.RemoveRange(
        _context.NumericDataPoints.Where(dp => dp.Timestamp < toTimestamp)
    );

    await _context.SaveChangesAsync();

    _logger.LogInformation(LoggingEvents.Clean.AsInt(), "Cleaned old data.");
}

问题

请建议我采取一般方法来实现考虑约束的目标。任何关于发布的代码和推理的反馈都表示赞赏!

0 个答案:

没有答案