From 1560c6bf91c75bb0f5cc35f0977a34ff018b862a Mon Sep 17 00:00:00 2001 From: Frolov-Nikita Date: Sun, 8 Oct 2023 21:20:28 +0500 Subject: [PATCH] Refactor webStore --- .../Data}/BackgroudWorkDto.cs | 41 +++- .../Background/BackgroundWorker.cs | 97 ++++------ .../Background/{WorkBase.cs => Work.cs} | 11 +- .../Background/WorkPeriodic.cs | 63 +++--- .../Background/WorkStore.cs | 183 +++++++----------- .../OperationDetectionWorkFactory.cs | 19 +- .../DrillingProgram/DrillingProgramService.cs | 8 +- .../EmailNotificationTransportService.cs | 6 +- .../LimitingParameterBackgroundService.cs | 7 +- .../Services/ReportService.cs | 4 +- .../Services/SAUB/TelemetryDataCache.cs | 6 +- .../SubsystemOperationTimeCalcWorkFactory.cs | 13 +- .../Services/WellInfoService.cs | 13 +- AsbCloudInfrastructure/Startup.cs | 17 +- .../DrillingProgramServiceTest.cs | 2 +- .../SignalRNotificationTransportService.cs | 6 +- 16 files changed, 219 insertions(+), 277 deletions(-) rename {AsbCloudInfrastructure/Background => AsbCloudApp/Data}/BackgroudWorkDto.cs (79%) rename AsbCloudInfrastructure/Background/{WorkBase.cs => Work.cs} (88%) diff --git a/AsbCloudInfrastructure/Background/BackgroudWorkDto.cs b/AsbCloudApp/Data/BackgroudWorkDto.cs similarity index 79% rename from AsbCloudInfrastructure/Background/BackgroudWorkDto.cs rename to AsbCloudApp/Data/BackgroudWorkDto.cs index 873217eb..64451d26 100644 --- a/AsbCloudInfrastructure/Background/BackgroudWorkDto.cs +++ b/AsbCloudApp/Data/BackgroudWorkDto.cs @@ -1,8 +1,11 @@ using System; using System.Diagnostics; -namespace AsbCloudInfrastructure.Background +namespace AsbCloudApp.Data { + /// + /// Информация о фоновой работе + /// public class BackgroudWorkDto { /// @@ -10,6 +13,9 @@ namespace AsbCloudInfrastructure.Background /// public string Id { get; init; } = null!; + /// + /// Класс описания состояния + /// public class CurrentStateInfo { private string state = "start"; @@ -37,6 +43,9 @@ namespace AsbCloudInfrastructure.Background } } + /// + /// Прогресс + /// public double Progress { get; internal set; } = 0; /// @@ -45,9 +54,12 @@ namespace AsbCloudInfrastructure.Background public DateTime StateUpdate { get; private set; } = DateTime.Now; } - public class LastErrorInfo: LastCompleteInfo + /// + /// Инфо о последней ошибке + /// + public class LastErrorInfo : LastCompleteInfo { - public LastErrorInfo(CurrentStateInfo state, string errorText) + public LastErrorInfo(CurrentStateInfo state, string errorText) : base(state) { ErrorText = errorText; @@ -59,12 +71,15 @@ namespace AsbCloudInfrastructure.Background public string ErrorText { get; init; } = null!; } + /// + /// Инфо о последнем завершении + /// public class LastCompleteInfo { /// /// Дата запуска /// - public DateTime Start {get; init;} + public DateTime Start { get; init; } /// /// Дата завершения @@ -123,9 +138,12 @@ namespace AsbCloudInfrastructure.Background /// Максимально допустимое время выполнения работы /// public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1); - + private string WorkNameForTrace => $"Backgroud work:\"{Id}\""; + /// + /// Обновления состояния при запуске работы + /// protected void SetStatusStart() { CurrentState = new(); @@ -133,6 +151,9 @@ namespace AsbCloudInfrastructure.Background Trace.TraceInformation($"{WorkNameForTrace} state: starting"); } + /// + /// Обновления состояния в процессе работы + /// protected void UpdateStatus(string newState, double? progress) { if (CurrentState is null) @@ -145,17 +166,23 @@ namespace AsbCloudInfrastructure.Background Trace.TraceInformation($"{WorkNameForTrace} state: {newState}"); } - protected void SetStatusComplete(System.Threading.Tasks.TaskStatus status) + /// + /// Обновления состояния при успешном завершении работы + /// + protected void SetStatusComplete() { if (CurrentState is null) return; - LastComplete = new (CurrentState); + LastComplete = new(CurrentState); CurrentState = null; CountComplete++; Trace.TraceInformation($"{WorkNameForTrace} state: completed"); } + /// + /// Обновления состояния при ошибке в работе + /// protected void SetLastError(string errorMessage) { if (CurrentState is null) diff --git a/AsbCloudInfrastructure/Background/BackgroundWorker.cs b/AsbCloudInfrastructure/Background/BackgroundWorker.cs index fad61edf..f4ef8c0e 100644 --- a/AsbCloudInfrastructure/Background/BackgroundWorker.cs +++ b/AsbCloudInfrastructure/Background/BackgroundWorker.cs @@ -1,78 +1,49 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -namespace AsbCloudInfrastructure.Background +namespace AsbCloudInfrastructure.Background; + +/// +/// Сервис для фонового выполнения работы +/// +public class BackgroundWorker : BackgroundService { - /// - /// Сервис для фонового выполнения работы - /// - public class BackgroundWorker : BackgroundService + private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10); + private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2); + private readonly IServiceProvider serviceProvider; + + public WorkStore WorkStore { get; } = new WorkStore(); + public Work? CurrentWork; + + public BackgroundWorker(IServiceProvider serviceProvider) { - private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10); - private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2); - private readonly IServiceProvider serviceProvider; - private readonly WorkStore workQueue = new WorkStore(); - public string? CurrentWorkId; + this.serviceProvider = serviceProvider; + } - public BackgroundWorker(IServiceProvider serviceProvider) + protected override async Task ExecuteAsync(CancellationToken token) + { + while (!token.IsCancellationRequested) { - this.serviceProvider = serviceProvider; - } - - /// - /// Добавление задачи в очередь. - /// Не периодические задачи будут выполняться вперед. - /// - /// - /// Id mast be unique - public void Push(WorkBase work) - { - workQueue.Push(work); - } - - /// - /// Проверяет наличие работы с указанным Id - /// - /// - /// - public bool Contains(string id) - { - return workQueue.Contains(id); - } - - /// - /// Удаление работы по ID - /// - /// - /// - public bool Delete(string id) - { - return workQueue.Delete(id); - } - - protected override async Task ExecuteAsync(CancellationToken token) - { - while (!token.IsCancellationRequested) + var work = WorkStore.GetNext(); + if (work is null) { - var work = workQueue.Pop(); - if (work is null) - { - await Task.Delay(executePeriod, token); - continue; - } - - CurrentWorkId = work.Id; - using var scope = serviceProvider.CreateScope(); - - await work.Start(scope.ServiceProvider, token); - - CurrentWorkId = null; - await Task.Delay(minDelay, token); + await Task.Delay(executePeriod, token); + continue; } + + CurrentWork = work; + using var scope = serviceProvider.CreateScope(); + + var result = await work.Start(scope.ServiceProvider, token); + + if (!result) + WorkStore.Falled.Add(work); + + CurrentWork = null; + await Task.Delay(minDelay, token); } } } diff --git a/AsbCloudInfrastructure/Background/WorkBase.cs b/AsbCloudInfrastructure/Background/Work.cs similarity index 88% rename from AsbCloudInfrastructure/Background/WorkBase.cs rename to AsbCloudInfrastructure/Background/Work.cs index e1b83053..84135707 100644 --- a/AsbCloudInfrastructure/Background/WorkBase.cs +++ b/AsbCloudInfrastructure/Background/Work.cs @@ -1,4 +1,5 @@ -using System; +using AsbCloudApp.Data; +using System; using System.Threading; using System.Threading.Tasks; @@ -8,9 +9,9 @@ namespace AsbCloudInfrastructure.Background /// Класс разовой работы. /// Разовая работа приоритетнее периодической. /// - public class WorkBase : BackgroudWorkDto + public class Work : BackgroudWorkDto { - internal Func, CancellationToken, Task> ActionAsync { get; } + private Func, CancellationToken, Task> ActionAsync { get; } /// /// Делегат обработки ошибки. @@ -48,7 +49,7 @@ namespace AsbCloudInfrastructure.Background /// /// /// - public WorkBase(string id, Func, CancellationToken, Task> actionAsync) + public Work(string id, Func, CancellationToken, Task> actionAsync) { Id = id; ActionAsync = actionAsync; @@ -67,7 +68,7 @@ namespace AsbCloudInfrastructure.Background { var task = ActionAsync(Id, services, UpdateStatus, token); await task.WaitAsync(Timeout, token); - SetStatusComplete(task.Status); + SetStatusComplete(); return true; } catch (Exception exception) diff --git a/AsbCloudInfrastructure/Background/WorkPeriodic.cs b/AsbCloudInfrastructure/Background/WorkPeriodic.cs index 71d580ed..4cd22af6 100644 --- a/AsbCloudInfrastructure/Background/WorkPeriodic.cs +++ b/AsbCloudInfrastructure/Background/WorkPeriodic.cs @@ -1,45 +1,42 @@ using System; -using System.Threading; -using System.Threading.Tasks; -namespace AsbCloudInfrastructure.Background +namespace AsbCloudInfrastructure.Background; + +/// +/// Класс периодической работы. +/// +public class WorkPeriodic { + public Work Work { get; } /// - /// Класс периодической работы. + /// Период выполнения задачи /// - public class WorkPeriodic : WorkBase + public TimeSpan Period { get; set; } + + /// + /// Время следующего запуска + /// + public DateTime NextStart { - /// - /// Период выполнения задачи - /// - public TimeSpan Period { get; set; } - - /// - /// Время следующего запуска - /// - public DateTime NextStart + get { - get - { - var lastStart = LastComplete?.Start ?? DateTime.MinValue; - if (LastError?.Start > lastStart) - lastStart = LastError.Start; - return lastStart + Period; - } - } - - /// - /// Класс периодической работы - /// - /// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки - /// Делегат работы - /// Период выполнения задачи - public WorkPeriodic(string id, Func, CancellationToken, Task> actionAsync, TimeSpan period) - : base(id, actionAsync) - { - Period = period; + var lastStart = Work.LastComplete?.Start ?? DateTime.MinValue; + if (Work.LastError?.Start > lastStart) + lastStart = Work.LastError.Start; + return lastStart + Period; } } + /// + /// Класс периодической работы + /// + /// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки + /// Делегат работы + /// Период выполнения задачи + public WorkPeriodic(Work work, TimeSpan period) + { + Work = work; + Period = period; + } } diff --git a/AsbCloudInfrastructure/Background/WorkStore.cs b/AsbCloudInfrastructure/Background/WorkStore.cs index 590ad8a6..dbb1e464 100644 --- a/AsbCloudInfrastructure/Background/WorkStore.cs +++ b/AsbCloudInfrastructure/Background/WorkStore.cs @@ -2,118 +2,85 @@ using System.Collections.Generic; using System.Linq; -namespace AsbCloudInfrastructure.Background +namespace AsbCloudInfrastructure.Background; + +/// +/// +/// Очередь работ +/// +/// Не периодические задачи будут возвращаться первыми, как самые приоритетные. +/// +public class WorkStore { + private readonly List periodics = new(8); + /// - /// - /// Очередь работ - /// - /// Не периодические задачи будут возвращаться первыми, как самые приоритетные. + /// Список периодических задач /// - class WorkStore + public IEnumerable Periodics => periodics; + /// + /// Работы выполняемые один раз + /// + public Queue RunOnceQueue { get; private set; } = new(8); + + /// + /// Завершывшиеся с ошибкой + /// + public CyclycArray Falled { get; } = new(16); + + public void AddPeriodic(Work work, TimeSpan period) { - private readonly List Periodic = new(8); - - /// - /// Работы выполняемые один раз - /// - public Queue RunOnceQueue { get; } = new(8); - - /// - /// Работы выполняемые периодически - /// - public IOrderedEnumerable Periodics => Periodic.OrderBy(work => work.NextStart); - - /// - /// Завершывшиеся с ошибкой - /// - public CyclycArray Falled { get; } = new(16); - - /// - /// Добавление работы. - /// - /// - /// Id mast be unique - public void Push(WorkBase work) - { - if (Periodic.Any(w => w.Id == work.Id)) - throw new ArgumentException("work.Id is not unique", nameof(work)); - - //if (Primary.Any(w => w.Id == work.Id)) - // throw new ArgumentException("work.Id is not unique", nameof(work)); - - if (work is WorkPeriodic workPeriodic) - { - Periodic.Add(workPeriodic); - return; - } - - //Primary.Enqueue(work); - } - - /// - /// Удаление работы по ID - /// - /// - /// - public bool Delete(string id) - { - var workPeriodic = Periodic.FirstOrDefault(w => w.Id == id); - if (workPeriodic is not null) - { - Periodic.Remove(workPeriodic); - return true; - } - - //var work = Primary.FirstOrDefault(w => w.Id == id); - //if (work is not null) - //{ - // Primary = new Queue(Primary.Where(w => w.Id != id)); - // return true; - //} - - return false; - } - - public bool Contains(string id) - { - var result = false;//Periodic.Any(w => w.Id == id) || Primary.Any(w => w.Id == id); - return result; - } - - /// - /// - /// Возвращает приоритетную задачу. - /// - /// - /// Если приоритетные закончились, то ищет ближайшую периодическую. - /// Если до старта ближайшей периодической работы меньше 20 сек, - /// то этой задаче устанавливается время последнего запуска в now и она возвращается. - /// Если больше 20 сек, то возвращается null. - /// - /// - /// - /// - public WorkBase? Pop() - { - //if (Primary.Any()) - // return Primary.Dequeue(); - - var work = GetNextPeriodic(); - if (work is null || work.NextStart > DateTime.Now) - return null; - - return work; - } - - private WorkPeriodic? GetNextPeriodic() - { - var work = Periodic - .OrderBy(w => w.NextStart) - .ThenByDescending(w => w.Period) - .FirstOrDefault(); - return work; - } + var periodic = new WorkPeriodic(work, period); + periodics.Add(periodic); } + /// + /// Удаление работы по ID из одноразовой очереди + /// + /// + /// + public bool TryRemoveFromRunOnceQueue(string id) + { + var work = RunOnceQueue.FirstOrDefault(w => w.Id == id); + if (work is not null) + { + RunOnceQueue = new Queue(RunOnceQueue.Where(w => w.Id != id)); + return true; + } + + return false; + } + + /// + /// + /// Возвращает приоритетную задачу. + /// + /// + /// Если приоритетные закончились, то ищет ближайшую периодическую. + /// Если до старта ближайшей периодической работы меньше 20 сек, + /// то этой задаче устанавливается время последнего запуска в now и она возвращается. + /// Если больше 20 сек, то возвращается null. + /// + /// + /// + /// + public Work? GetNext() + { + if (RunOnceQueue.Any()) + return RunOnceQueue.Dequeue(); + + var work = GetNextPeriodic(); + if (work is null || work.NextStart > DateTime.Now) + return null; + + return work.Work; + } + + private WorkPeriodic? GetNextPeriodic() + { + var work = Periodics + .OrderBy(w => w.NextStart) + .FirstOrDefault(); + return work; + } } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs b/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs index 350ad6b7..0c9bb3dd 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs @@ -16,7 +16,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations public static class OperationDetectionWorkFactory { private const string workId = "Operation detection"; - private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30); private static string progress = "no progress"; private static readonly DetectorAbstract[] detectors = new DetectorAbstract[] @@ -32,18 +31,16 @@ namespace AsbCloudInfrastructure.Services.DetectOperations //new DetectorTemplatingWhileDrilling(), }; - public static WorkPeriodic MakeWork() - { - var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod); - workPeriodic.Timeout = TimeSpan.FromSeconds(15 * 60); - workPeriodic.OnErrorAsync = (id, exception, token) => + public static Work MakeWork() => new Work(workId, WorkAction) { - var text = $"work {id}, when {progress}, throw error:{exception.Message}"; - Trace.TraceWarning(text); - return Task.CompletedTask; + Timeout = TimeSpan.FromMinutes(20), + OnErrorAsync = (id, exception, token) => + { + var text = $"work {id}, when {progress}, throw error:{exception.Message}"; + Trace.TraceWarning(text); + return Task.CompletedTask; + } }; - return workPeriodic; - } // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД. private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action onProgress, CancellationToken token) diff --git a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs index cf41ab7c..402a89ed 100644 --- a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs +++ b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs @@ -513,7 +513,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram if (state.IdState == idStateCreating) { var workId = MakeWorkId(idWell); - if (!backgroundWorker.Contains(workId)) + if (!backgroundWorker.WorkStore.RunOnceQueue.Any(w => w.Id == workId)) { var well = (await wellService.GetOrDefaultAsync(idWell, token))!; var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.pdf"; @@ -540,12 +540,12 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram return Task.CompletedTask; }; - var work = new WorkBase(workId, workAction) + var work = new Work(workId, workAction) { OnErrorAsync = onErrorAction }; - backgroundWorker.Push(work); + backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work); } } } @@ -559,7 +559,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram private async Task RemoveDrillingProgramAsync(int idWell, CancellationToken token) { var workId = MakeWorkId(idWell); - backgroundWorker.Delete(workId); + backgroundWorker.WorkStore.TryRemoveFromRunOnceQueue(workId); var filesIds = await context.Files .Where(f => f.IdWell == idWell && diff --git a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs index 412a4354..33f011bf 100644 --- a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs +++ b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs @@ -52,12 +52,12 @@ namespace AsbCloudInfrastructure.Services.Email } var workId = MakeWorkId(notification.IdUser, notification.Title, notification.Message); - if (!backgroundWorker.Contains(workId)) + if (!backgroundWorker.WorkStore.RunOnceQueue.Any(w=>w.Id==workId)) { var workAction = MakeEmailSendWorkAction(notification); - var work = new WorkBase(workId, workAction); - backgroundWorker.Push(work); + var work = new Work(workId, workAction); + backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work); } return Task.CompletedTask; diff --git a/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs b/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs index 6c4f94c1..07a17369 100644 --- a/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs +++ b/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs @@ -16,16 +16,11 @@ namespace AsbCloudInfrastructure.Services internal static class LimitingParameterCalcWorkFactory { private const string workId = "Limiting parameter calc"; - private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30); - public static WorkPeriodic MakeWork() - { - var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod) + public static Work MakeWork() => new Work(workId, WorkAction) { Timeout = TimeSpan.FromMinutes(30) }; - return workPeriodic; - } // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД. private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action onProgress, CancellationToken token) diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs index 95851c74..f3ab6cb8 100644 --- a/AsbCloudInfrastructure/Services/ReportService.cs +++ b/AsbCloudInfrastructure/Services/ReportService.cs @@ -94,8 +94,8 @@ namespace AsbCloudInfrastructure.Services context.SaveChanges(); }; - var work = new WorkBase(workId, workAction); - backgroundWorkerService.Push(work); + var work = new Work(workId, workAction); + backgroundWorkerService.WorkStore.RunOnceQueue.Enqueue(work); progressHandler.Invoke(new ReportProgressDto { diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 8868fc24..daaa2dcf 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -48,12 +48,12 @@ namespace AsbCloudInfrastructure.Services.SAUB instance = new TelemetryDataCache(); var worker = provider.GetRequiredService(); var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; - var work = new WorkBase(workId, async (workId, provider, onProgress, token) => { + var work = new Work(workId, async (workId, provider, onProgress, token) => { var db = provider.GetRequiredService(); await instance.InitializeCacheFromDBAsync(db, onProgress, token); }); - worker.Push(work); + worker.WorkStore.RunOnceQueue.Enqueue(work); } instance.provider = provider; return instance; @@ -168,7 +168,7 @@ namespace AsbCloudInfrastructure.Services.SAUB .Where(well => well.IdTelemetry != null) .ToArrayAsync(token); - var count = wells.Count(); + var count = wells.Length; var i = 0; foreach (Well well in wells) { diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs index bbbc1fb5..451ca633 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs @@ -18,7 +18,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems internal static class SubsystemOperationTimeCalcWorkFactory { private const string workId = "Subsystem operation time calc"; - private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30); private const int idSubsytemTorqueMaster = 65537; private const int idSubsytemSpinMaster = 65536; @@ -26,14 +25,10 @@ namespace AsbCloudInfrastructure.Services.Subsystems private const int idSubsystemAPDSlide = 12; private const int idSubsytemMse = 2; - public static WorkPeriodic MakeWork() - { - var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod) - { - Timeout = TimeSpan.FromMinutes(30) - }; - return workPeriodic; - } + public static Work MakeWork() => new Work(workId, WorkAction) + { + Timeout = TimeSpan.FromMinutes(20) + }; // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД. private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action onProgress, CancellationToken token) diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs index 0d6951b2..80456db9 100644 --- a/AsbCloudInfrastructure/Services/WellInfoService.cs +++ b/AsbCloudInfrastructure/Services/WellInfoService.cs @@ -29,7 +29,6 @@ namespace AsbCloudInfrastructure.Services } private const string workId = "Well statistics update"; - private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30); private readonly TelemetryDataCache telemetryDataSaubCache; private readonly TelemetryDataCache telemetryDataSpinCache; @@ -53,14 +52,10 @@ namespace AsbCloudInfrastructure.Services this.gtrRepository = gtrRepository; } - public static WorkPeriodic MakeWork() - { - var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod) - { - Timeout = TimeSpan.FromMinutes(30) - }; - return workPeriodic; - } + public static Work MakeWork() => new Work(workId, WorkAction) + { + Timeout = TimeSpan.FromMinutes(20) + }; private static async Task WorkAction(string workName, IServiceProvider serviceProvider, Action onProgress, CancellationToken token) { diff --git a/AsbCloudInfrastructure/Startup.cs b/AsbCloudInfrastructure/Startup.cs index 54d5d080..604a4f69 100644 --- a/AsbCloudInfrastructure/Startup.cs +++ b/AsbCloudInfrastructure/Startup.cs @@ -15,7 +15,6 @@ using AsbCloudInfrastructure.Services.SAUB; namespace AsbCloudInfrastructure { - public class Startup { public static void BeforeRunHandler(IHost host) @@ -32,11 +31,11 @@ namespace AsbCloudInfrastructure _ = provider.GetRequiredService>(); var backgroundWorker = provider.GetRequiredService(); - backgroundWorker.Push(WellInfoService.MakeWork()); - backgroundWorker.Push(OperationDetectionWorkFactory.MakeWork()); - backgroundWorker.Push(SubsystemOperationTimeCalcWorkFactory.MakeWork()); - backgroundWorker.Push(LimitingParameterCalcWorkFactory.MakeWork()); - backgroundWorker.Push(MakeMemoryMonitoringWork()); + backgroundWorker.WorkStore.AddPeriodic(WellInfoService.MakeWork(), TimeSpan.FromMinutes(30)); + backgroundWorker.WorkStore.AddPeriodic(OperationDetectionWorkFactory.MakeWork(), TimeSpan.FromMinutes(15)); + backgroundWorker.WorkStore.AddPeriodic(SubsystemOperationTimeCalcWorkFactory.MakeWork(), TimeSpan.FromMinutes(30)); + backgroundWorker.WorkStore.AddPeriodic(LimitingParameterCalcWorkFactory.MakeWork(), TimeSpan.FromMinutes(30)); + backgroundWorker.WorkStore.AddPeriodic(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1)); var notificationBackgroundWorker = provider.GetRequiredService(); @@ -48,17 +47,15 @@ namespace AsbCloudInfrastructure }); } - static WorkPeriodic MakeMemoryMonitoringWork() + static Work MakeMemoryMonitoringWork() { - var workId = "Memory monitoring"; var workAction = (string _, IServiceProvider _, Action _, CancellationToken _) => { var bytes = GC.GetTotalMemory(false); var bytesString = FromatBytes(bytes); System.Diagnostics.Trace.TraceInformation($"Total memory allocated is {bytesString} bytes. DbContext count is:{AsbCloudDbContext.ReferenceCount}"); return Task.CompletedTask; }; - var workPeriod = TimeSpan.FromMinutes(1); - var work = new WorkPeriodic(workId, workAction, workPeriod); + var work = new Work("Memory monitoring", workAction); return work; } diff --git a/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs index 12bc81a2..54f5d19c 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs @@ -366,7 +366,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None); Assert.Equal(2, state.IdState); - backgroundWorkerMock.Verify(s => s.Push(It.IsAny())); + backgroundWorkerMock.Verify(s => s.Push(It.IsAny())); } [Fact] diff --git a/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs b/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs index 9633eb1c..143055e5 100644 --- a/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs +++ b/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs @@ -29,12 +29,12 @@ public class SignalRNotificationTransportService : INotificationTransportService { var workId = HashCode.Combine(notifications.Select(n => n.Id)).ToString("x"); - if (backgroundWorker.Contains(workId)) + if (backgroundWorker.WorkStore.RunOnceQueue.Any(w => w.Id == workId)) return Task.CompletedTask; var workAction = MakeSignalRSendWorkAction(notifications); - var work = new WorkBase(workId, workAction); - backgroundWorker.Push(work); + var work = new Work(workId, workAction); + backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work); return Task.CompletedTask; }