DD.WellWorkover.Cloud/AsbCloudInfrastructure/Background/BackgroundWorker.cs
ngfrolov 17c13b7a7b
spell
nit refactoring by VS recommendations
2023-12-05 14:48:56 +05:00

124 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 BackgroundWorker : BackgroundService
{
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
private readonly IServiceProvider serviceProvider;
/// <summary>
/// Очередь работ
/// </summary>
private Queue<Work> works = new(8);
/// <summary>
/// Список периодических работ
/// </summary>
public IEnumerable<Work> Works => works;
/// <summary>
/// Работа выполняемая в данный момент
/// </summary>
public Work? CurrentWork;
private bool isRuning;
/// <summary>
/// последние 16 завершившиеся с ошибкой
/// </summary>
public CyclicArray<Work> Felled { get; } = new(16);
/// <summary>
/// последние 16 успешно завершенных
/// </summary>
public CyclicArray<Work> Done { get; } = new(16);
/// <summary>
/// Ошибка в главном цикле, никогда не должна появляться
/// </summary>
public string MainLoopLastException { get; private set; } = string.Empty;
public BackgroundWorker(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 && works.TryDequeue(out CurrentWork))
{
try
{
using var scope = serviceProvider.CreateScope();
var result = await CurrentWork.Start(scope.ServiceProvider, token);
if (!result)
Felled.Add(CurrentWork);
else
Done.Add(CurrentWork);
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>
/// Добавить в очередь
/// <para>
/// work.Id может быть не уникальным,
/// при этом метод TryRemoveFromQueue удалит все работы с совпадающими id
/// </para>
/// </summary>
/// <param name="work"></param>
public void Enqueue(Work work)
{
works.Enqueue(work);
if (ExecuteTask is null || ExecuteTask.IsCompleted)
StartAsync(CancellationToken.None);
}
/// <summary>
/// Удаление работы по ID из одноразовой очереди
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool TryRemoveFromQueue(string id)
{
var work = Works.FirstOrDefault(w => w.Id == id);
if (work is not null)
{
works = new Queue<Work>(Works.Where(w => w.Id != id));
return true;
}
return false;
}
}