DD.WellWorkover.Cloud/AsbCloudInfrastructure/Background/PeriodicBackgroundWorker.cs
2023-11-28 16:31:31 +05:00

121 lines
3.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background;
/// <summary>
/// Сервис для фонового выполнения периодической работы
/// </summary>
public class PeriodicBackgroundWorker : BackgroundService
{
private readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
private readonly IServiceProvider serviceProvider;
private readonly List<WorkPeriodic> works = new(8);
private bool isRuning = false;
/// <summary>
/// Список периодических работ
/// </summary>
public IEnumerable<WorkPeriodic> Works => works;
/// <summary>
/// Работа выполняемая в данный момент
/// </summary>
public Work? CurrentWork;
/// <summary>
/// Ошибка в главном цикле, никогда не должна появляться
/// </summary>
public string MainLoopLastException { get; private set; } = string.Empty;
public PeriodicBackgroundWorker(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken token)
{
if (isRuning)
return;
isRuning = true;
Trace.TraceInformation($"{GetType().Name} started");
while (!token.IsCancellationRequested)
{
try
{
var periodicWork = GetNext();
if (periodicWork is null)
{
await Task.Delay(executePeriod, token);
continue;
}
CurrentWork = periodicWork.Work;
using var scope = serviceProvider.CreateScope();
var result = await periodicWork.Work.Start(scope.ServiceProvider, token);
CurrentWork = null;
await Task.Delay(minDelay, token);
}
catch (Exception ex)
{
MainLoopLastException = $"BackgroundWorker " +
$"MainLoopLastException: \r\n" +
$"date: {DateTime.Now:O}\r\n" +
$"message: {ex.Message}\r\n" +
$"inner: {ex.InnerException?.Message}\r\n" +
$"stackTrace: {ex.StackTrace}";
Trace.TraceError(MainLoopLastException);
}
}
isRuning = false;
}
/// <summary>
/// Добавить фоновую работу выполняющуюся с заданным периодом
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="period"></param>
public void Add<T>(TimeSpan period)
where T : Work, new()
{
var work = new T();
var periodic = new WorkPeriodic(work, period);
works.Add(periodic);
}
/// <summary>
/// Добавить фоновую работу выполняющуюся с заданным периодом
/// </summary>
/// <param name="work"></param>
/// <param name="period"></param>
public void Add(Work work, TimeSpan period)
{
var periodic = new WorkPeriodic(work, period);
works.Add(periodic);
if (ExecuteTask is null || ExecuteTask.IsCompleted)
StartAsync(CancellationToken.None).Wait();
}
private WorkPeriodic? GetNext()
{
var work = works
.OrderBy(w => w.NextStart)
.FirstOrDefault();
if (work is null || work.NextStart > DateTime.Now)
return null;
return work;
}
}