2022-12-02 14:45:20 +05:00
|
|
|
|
using System;
|
2023-10-08 13:09:09 +05:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Text;
|
2022-12-02 14:45:20 +05:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure.Background
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Класс разовой работы.
|
|
|
|
|
/// Разовая работа приоритетнее периодической.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class WorkBase
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки.
|
|
|
|
|
/// </summary>
|
2023-10-08 13:09:09 +05:00
|
|
|
|
public string Id { get; }
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
|
|
|
|
/// <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>
|
2023-10-08 13:09:09 +05:00
|
|
|
|
internal Func<string, IServiceProvider, CancellationToken, Task> ActionAsync { get; }
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Делегат обработки ошибки.
|
|
|
|
|
/// Не должен выполняться долго.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Func<string, Exception, CancellationToken, Task>? OnErrorAsync { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// максимально допустимое время выполнения работы
|
|
|
|
|
/// </summary>
|
|
|
|
|
public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2023-10-08 13:09:09 +05:00
|
|
|
|
/// Продолжительность последнего выполнения
|
|
|
|
|
/// </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>
|
|
|
|
|
/// Текстовое описание того, что происходит в задаче.
|
2022-12-02 14:45:20 +05:00
|
|
|
|
/// </summary>
|
2023-10-08 13:09:09 +05:00
|
|
|
|
public string? CurrentStatus { get; private set; }
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Время последнего запуска
|
|
|
|
|
/// </summary>
|
2023-10-08 13:09:09 +05:00
|
|
|
|
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}\"";
|
2022-12-02 14:45:20 +05:00
|
|
|
|
|
|
|
|
|
public WorkBase(string id, Func<string, IServiceProvider, CancellationToken, Task> actionAsync)
|
|
|
|
|
{
|
|
|
|
|
Id = id;
|
|
|
|
|
ActionAsync = actionAsync;
|
|
|
|
|
}
|
2023-10-08 13:09:09 +05:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2023-04-18 16:22:53 +05:00
|
|
|
|
|
2023-10-08 13:09:09 +05:00
|
|
|
|
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}");
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-02 14:45:20 +05:00
|
|
|
|
}
|