2022-12-05 10:53:24 +05:00
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2022-12-02 14:45:20 +05:00
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
using System;
|
2023-11-03 17:02:44 +05:00
|
|
|
|
using System.Collections.Generic;
|
2023-11-02 16:20:48 +05:00
|
|
|
|
using System.Diagnostics;
|
2023-11-03 17:02:44 +05:00
|
|
|
|
using System.Linq;
|
2022-12-02 14:45:20 +05:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
2023-10-08 21:20:28 +05:00
|
|
|
|
namespace AsbCloudInfrastructure.Background;
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
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;
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
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;
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
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>
|
2023-11-02 17:40:51 +05:00
|
|
|
|
public string MainLoopLastException { get; private set; } = string.Empty;
|
2023-11-02 16:20:48 +05:00
|
|
|
|
|
2023-10-08 21:20:28 +05:00
|
|
|
|
public BackgroundWorker(IServiceProvider serviceProvider)
|
|
|
|
|
{
|
|
|
|
|
this.serviceProvider = serviceProvider;
|
|
|
|
|
}
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
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))
|
2022-12-02 14:45:20 +05:00
|
|
|
|
{
|
2023-11-02 16:20:48 +05:00
|
|
|
|
try
|
2022-12-02 14:45:20 +05:00
|
|
|
|
{
|
2023-11-02 16:20:48 +05:00
|
|
|
|
using var scope = serviceProvider.CreateScope();
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
2023-11-03 17:02:44 +05:00
|
|
|
|
var result = await CurrentWork.Start(scope.ServiceProvider, token);
|
2023-10-08 13:09:09 +05:00
|
|
|
|
|
2023-11-02 16:20:48 +05:00
|
|
|
|
if (!result)
|
2023-11-03 17:02:44 +05:00
|
|
|
|
Felled.Add(CurrentWork);
|
2023-11-02 16:20:48 +05:00
|
|
|
|
else
|
2023-11-03 17:02:44 +05:00
|
|
|
|
Done.Add(CurrentWork);
|
2023-10-08 21:20:28 +05:00
|
|
|
|
|
2023-11-02 16:20:48 +05:00
|
|
|
|
CurrentWork = null;
|
|
|
|
|
await Task.Delay(minDelay, token);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2023-11-02 17:40:51 +05:00
|
|
|
|
MainLoopLastException = $"BackgroundWorker " +
|
2023-11-02 16:20:48 +05:00
|
|
|
|
$"MainLoopLastException: \r\n" +
|
|
|
|
|
$"date: {DateTime.Now:O}\r\n" +
|
|
|
|
|
$"message: {ex.Message}\r\n" +
|
|
|
|
|
$"inner: {ex.InnerException?.Message}\r\n" +
|
|
|
|
|
$"stackTrace: {ex.StackTrace}";
|
2023-11-02 17:40:51 +05:00
|
|
|
|
Trace.TraceError(MainLoopLastException);
|
2023-11-02 16:20:48 +05:00
|
|
|
|
}
|
2022-12-02 14:45:20 +05:00
|
|
|
|
}
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
2022-12-02 14:45:20 +05:00
|
|
|
|
}
|