.NET Core Console应用程序中的重复任务

简短的版本是 – 我如何(在2017年发布.NET Core 1.1)在Microsoft Core dependency injection的 .NET Core 控制台应用程序中运行重复任务?

长篇故事和代码片段。

目标

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

当前的脏实现

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

目前的问题

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

我想要的解决方案

我想实现目标,但如果可能的话

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

代码片段

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

 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() .Metrics .ToListAsync(); // Run the tasks var tasks = metrics .Select( (metric) => Task.Factory.StartNew(async () => { await _serviceProvider .GetRequiredService() .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."); } 

这个问题

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