DD.WellWorkover.Cloud/AsbCloudInfrastructure/Background/BackgroundWorker.cs

114 lines
3.4 KiB
C#
Raw Normal View History

2022-12-05 10:53:24 +05:00
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
2023-11-03 17:02:44 +05:00
using System.Collections.Generic;
using System.Diagnostics;
2023-11-03 17:02:44 +05:00
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
2023-10-08 21:20:28 +05:00
namespace AsbCloudInfrastructure.Background;
2023-10-08 21:20:28 +05:00
/// <summary>
/// Сервис для фонового выполнения работы
/// </summary>
public class BackgroundWorker : BackgroundService
{
2023-11-03 17:02:44 +05:00
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
2023-10-08 21:20:28 +05:00
private readonly IServiceProvider serviceProvider;
2023-11-03 17:02:44 +05:00
/// <summary>
/// Очередь работ
/// </summary>
private Queue<Work> works = new(8);
/// <summary>
/// Список периодических работ
/// </summary>
public IEnumerable<Work> Works => works;
/// <summary>
/// Работа выполняемая в данный момент
/// </summary>
2023-10-08 21:20:28 +05:00
public Work? CurrentWork;
2023-11-03 17:02:44 +05:00
/// <summary>
/// последние 16 завершившиеся с ошибкой
/// </summary>
public CyclycArray<Work> Felled { get; } = new(16);
/// <summary>
/// последние 16 успешно завершенных
/// </summary>
public CyclycArray<Work> Done { get; } = new(16);
/// <summary>
/// Ошибка в главном цикле, никогда не должна появляться
/// </summary>
public string MainLoopLastException { get; private set; } = string.Empty;
2023-10-08 21:20:28 +05:00
public BackgroundWorker(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
2023-11-03 17:02:44 +05:00
/// <summary>
/// Добавить в очередь
/// </summary>
/// <param name="work"></param>
public void Enqueue(Work work)
{
works.Enqueue(work);
if (ExecuteTask is null || ExecuteTask.IsCompleted)
StartAsync(CancellationToken.None).Wait();
}
2023-10-08 21:20:28 +05:00
protected override async Task ExecuteAsync(CancellationToken token)
{
2023-11-03 17:02:44 +05:00
while (!token.IsCancellationRequested && works.TryDequeue(out CurrentWork))
{
try
{
using var scope = serviceProvider.CreateScope();
2023-11-03 17:02:44 +05:00
var result = await CurrentWork.Start(scope.ServiceProvider, token);
if (!result)
2023-11-03 17:02:44 +05:00
Felled.Add(CurrentWork);
else
2023-11-03 17:02:44 +05:00
Done.Add(CurrentWork);
2023-10-08 21:20:28 +05:00
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);
}
}
}
2023-11-03 17:02:44 +05:00
/// <summary>
/// Удаление работы по ID из одноразовой очереди
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool TryRemoveFromRunOnceQueue(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;
}
}