using System; using System.Diagnostics; namespace AsbCloudApp.Data { /// <summary> /// Информация о фоновой работе /// </summary> public class BackgroundWorkDto { /// <summary> /// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки. /// </summary> public string Id { get; init; } = null!; /// <summary> /// Класс описания состояния /// </summary> public class CurrentStateInfo { private string state = "start"; /// <summary> /// Время последнего запуска /// </summary> public DateTime Start { get; } = DateTime.Now; /// <summary> /// Текущее время выполнения /// </summary> public TimeSpan ExecutionTime => DateTime.Now - Start; /// <summary> /// Текстовое описание того, что происходит в задаче. /// </summary> public string State { get => state; internal set { state = value; StateUpdate = DateTime.Now; } } /// <summary> /// Прогресс /// </summary> public double Progress { get; internal set; } = 0; /// <summary> /// Время последнего запуска /// </summary> public DateTime StateUpdate { get; private set; } = DateTime.Now; } /// <summary> /// Инфо о последней ошибке /// </summary> public class LastErrorInfo : LastCompleteInfo { /// <summary> /// /// </summary> /// <param name="state"></param> /// <param name="errorText"></param> public LastErrorInfo(CurrentStateInfo state, string errorText) : base(state) { ErrorText = errorText; } /// <summary> /// Последняя ошибка /// </summary> public string ErrorText { get; init; } = null!; } /// <summary> /// Инфо о последнем завершении /// </summary> public class LastCompleteInfo { /// <summary> /// Дата запуска /// </summary> public DateTime Start { get; init; } /// <summary> /// Дата завершения /// </summary> public DateTime End { get; init; } /// <summary> /// Продолжительность последнего выполнения /// </summary> public TimeSpan ExecutionTime => End - Start; /// <summary> /// Состояние на момент завершения /// </summary> public string State { get; init; } /// <summary> /// ctor /// </summary> /// <param name="state"></param> public LastCompleteInfo(CurrentStateInfo state) { Start = state.Start; End = DateTime.Now; State = state.State; } } /// <summary> /// Текущее состояние /// </summary> public CurrentStateInfo? CurrentState { get; private set; } /// <summary> /// Последняя ошибка /// </summary> public LastErrorInfo? LastError { get; private set; } /// <summary> /// Последняя завершенная /// </summary> public LastCompleteInfo? LastComplete { get; private set; } /// <summary> /// Кол-во запусков /// </summary> public int CountStart { get; private set; } /// <summary> /// Кол-во завершений /// </summary> public int CountComplete { get; private set; } /// <summary> /// Кол-во ошибок /// </summary> public int CountErrors { get; private set; } /// <summary> /// Максимально допустимое время выполнения работы /// </summary> public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1); private string WorkNameForTrace => $"Backgroud work:\"{Id}\""; /// <summary> /// Обновления состояния при запуске работы /// </summary> protected void SetStatusStart() { CurrentState = new(); CountStart++; Trace.TraceInformation($"{WorkNameForTrace} state: starting"); } /// <summary> /// Обновления состояния в процессе работы /// </summary> protected void UpdateStatus(string newState, double? progress) { if (CurrentState is null) return; CurrentState.State = newState; if (progress.HasValue) CurrentState.Progress = progress.Value; Trace.TraceInformation($"{WorkNameForTrace} state[{100*progress:#}%]: {newState}"); } /// <summary> /// Обновления состояния при успешном завершении работы /// </summary> protected void SetStatusComplete() { CountComplete++; if (CurrentState is null) return; LastComplete = new(CurrentState); CurrentState = null; Trace.TraceInformation($"{WorkNameForTrace} state: completed"); } /// <summary> /// Обновления состояния при ошибке в работе /// </summary> protected void SetLastError(string errorMessage) { CountErrors++; if (CurrentState is null) return; LastError = new LastErrorInfo(CurrentState, errorMessage); CurrentState = null; Trace.TraceError($"{WorkNameForTrace} throw exception[{CountErrors}]: {errorMessage}"); } } }