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

169 lines
5.8 KiB
C#
Raw Normal View History

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background
{
/// <summary>
/// Класс разовой работы.
/// Разовая работа приоритетнее периодической.
/// </summary>
public class WorkBase
{
/// <summary>
/// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки.
/// </summary>
public string Id { get; }
/// <summary>
/// Делегат работы.
/// <para>
/// Параметры:
/// <list type="number">
/// <item>
/// <term>string</term>
/// <description>Id Идентификатор работы</description>
/// </item>
/// <item>
/// <term>IServiceProvider</term>
/// <description>Поставщик сервисов</description>
/// </item>
/// <item>
/// <term>CancellationToken</term>
/// <description>Токен отмены задачи</description>
/// </item>
/// </list>
/// </para>
/// </summary>
internal Func<string, IServiceProvider, CancellationToken, Task> ActionAsync { get; }
/// <summary>
/// Делегат обработки ошибки.
/// Не должен выполняться долго.
/// </summary>
public Func<string, Exception, CancellationToken, Task>? OnErrorAsync { get; set; }
/// <summary>
/// максимально допустимое время выполнения работы
/// </summary>
public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);
/// <summary>
/// Продолжительность последнего выполнения
/// </summary>
public TimeSpan? LastExecutionTime { get; private set; }
/// <summary>
/// Текущее время выполнения
/// </summary>
public TimeSpan? CurrentExecutionTime => CurrentStart.HasValue
? DateTime.Now - CurrentStart.Value
: null;
/// <summary>
/// Время последнего запуска
/// </summary>
public DateTime? CurrentStart { get; private set; }
/// <summary>
/// Текстовое описание того, что происходит в задаче.
/// </summary>
public string? CurrentStatus { get; private set; }
/// <summary>
/// Время последнего запуска
/// </summary>
public DateTime? CurrentStatusUpdate { get; private set; }
/// <summary>
/// Последняя ошибка
/// </summary>
public string? LastErrorMessage { get; private set; }
/// <summary>
/// Дата последнего запуска
/// </summary>
public DateTime? LastStart { get; private set; }
/// <summary>
/// Дата последней ошибки
/// </summary>
public DateTime? LastError { get; private set; }
/// <summary>
/// Дата завершения последнего выполнения
/// </summary>
public DateTime? LastComplete { get; private set; }
/// <summary>
/// Кол-во завершений
/// </summary>
public int CountComplete { get; private set; }
/// <summary>
/// Кол-во ошибок
/// </summary>
public int CountErrors { get; private set; }
private string WorkNameForTrace => $"Backgroud work:\"{Id}\"";
public WorkBase(string id, Func<string, IServiceProvider, CancellationToken, Task> actionAsync)
{
Id = id;
ActionAsync = actionAsync;
}
public async Task Start(IServiceProvider services, CancellationToken token)
{
CurrentStart = DateTime.Now;
LastStart = DateTime.Now;
try
{
SetStatus(" start");
var task = ActionAsync(Id, services, token);
await task.WaitAsync(Timeout, token);
LastComplete = DateTime.Now;
CountComplete++;
SetStatus($" {task.Status}. ExecutionTime: {CurrentExecutionTime:hh\\:mm\\:ss\\.fff}");
}
catch (Exception exception)
{
SetError(exception.Message);
if (OnErrorAsync is not null)
{
var task = Task.Run(
async () => await OnErrorAsync(Id, exception, token),
token);
await task.WaitAsync(Timeout, token);
}
}
LastExecutionTime = CurrentExecutionTime;
CurrentStart = null;
SetStatus(null);
}
protected void SetStatus(string? newStatus)
{
CurrentStatus = newStatus;
if (newStatus is not null)
{
CurrentStatusUpdate = DateTime.Now;
Trace.TraceInformation($"{WorkNameForTrace} state: {newStatus}");
}
else
CurrentStatusUpdate = null;
}
private void SetError(string? errorMessage)
{
CountErrors++;
LastErrorMessage = errorMessage;
LastError = DateTime.Now;
Trace.TraceError($"{WorkNameForTrace} throw exception[{CountErrors}]: {errorMessage}");
}
}
}