Refactor webStore

This commit is contained in:
Frolov-Nikita 2023-10-08 21:20:28 +05:00
parent 724c7b0cd8
commit 1560c6bf91
No known key found for this signature in database
GPG Key ID: 719E3386D12B0760
16 changed files with 219 additions and 277 deletions

View File

@ -1,8 +1,11 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
namespace AsbCloudInfrastructure.Background namespace AsbCloudApp.Data
{ {
/// <summary>
/// Информация о фоновой работе
/// </summary>
public class BackgroudWorkDto public class BackgroudWorkDto
{ {
/// <summary> /// <summary>
@ -10,6 +13,9 @@ namespace AsbCloudInfrastructure.Background
/// </summary> /// </summary>
public string Id { get; init; } = null!; public string Id { get; init; } = null!;
/// <summary>
/// Класс описания состояния
/// </summary>
public class CurrentStateInfo public class CurrentStateInfo
{ {
private string state = "start"; private string state = "start";
@ -37,6 +43,9 @@ namespace AsbCloudInfrastructure.Background
} }
} }
/// <summary>
/// Прогресс
/// </summary>
public double Progress { get; internal set; } = 0; public double Progress { get; internal set; } = 0;
/// <summary> /// <summary>
@ -45,7 +54,10 @@ namespace AsbCloudInfrastructure.Background
public DateTime StateUpdate { get; private set; } = DateTime.Now; public DateTime StateUpdate { get; private set; } = DateTime.Now;
} }
public class LastErrorInfo: LastCompleteInfo /// <summary>
/// Инфо о последней ошибке
/// </summary>
public class LastErrorInfo : LastCompleteInfo
{ {
public LastErrorInfo(CurrentStateInfo state, string errorText) public LastErrorInfo(CurrentStateInfo state, string errorText)
: base(state) : base(state)
@ -59,12 +71,15 @@ namespace AsbCloudInfrastructure.Background
public string ErrorText { get; init; } = null!; public string ErrorText { get; init; } = null!;
} }
/// <summary>
/// Инфо о последнем завершении
/// </summary>
public class LastCompleteInfo public class LastCompleteInfo
{ {
/// <summary> /// <summary>
/// Дата запуска /// Дата запуска
/// </summary> /// </summary>
public DateTime Start {get; init;} public DateTime Start { get; init; }
/// <summary> /// <summary>
/// Дата завершения /// Дата завершения
@ -126,6 +141,9 @@ namespace AsbCloudInfrastructure.Background
private string WorkNameForTrace => $"Backgroud work:\"{Id}\""; private string WorkNameForTrace => $"Backgroud work:\"{Id}\"";
/// <summary>
/// Обновления состояния при запуске работы
/// </summary>
protected void SetStatusStart() protected void SetStatusStart()
{ {
CurrentState = new(); CurrentState = new();
@ -133,6 +151,9 @@ namespace AsbCloudInfrastructure.Background
Trace.TraceInformation($"{WorkNameForTrace} state: starting"); Trace.TraceInformation($"{WorkNameForTrace} state: starting");
} }
/// <summary>
/// Обновления состояния в процессе работы
/// </summary>
protected void UpdateStatus(string newState, double? progress) protected void UpdateStatus(string newState, double? progress)
{ {
if (CurrentState is null) if (CurrentState is null)
@ -145,17 +166,23 @@ namespace AsbCloudInfrastructure.Background
Trace.TraceInformation($"{WorkNameForTrace} state: {newState}"); Trace.TraceInformation($"{WorkNameForTrace} state: {newState}");
} }
protected void SetStatusComplete(System.Threading.Tasks.TaskStatus status) /// <summary>
/// Обновления состояния при успешном завершении работы
/// </summary>
protected void SetStatusComplete()
{ {
if (CurrentState is null) if (CurrentState is null)
return; return;
LastComplete = new (CurrentState); LastComplete = new(CurrentState);
CurrentState = null; CurrentState = null;
CountComplete++; CountComplete++;
Trace.TraceInformation($"{WorkNameForTrace} state: completed"); Trace.TraceInformation($"{WorkNameForTrace} state: completed");
} }
/// <summary>
/// Обновления состояния при ошибке в работе
/// </summary>
protected void SetLastError(string errorMessage) protected void SetLastError(string errorMessage)
{ {
if (CurrentState is null) if (CurrentState is null)

View File

@ -1,78 +1,49 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using System; using System;
using System.Diagnostics;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background namespace AsbCloudInfrastructure.Background;
/// <summary>
/// Сервис для фонового выполнения работы
/// </summary>
public class BackgroundWorker : BackgroundService
{ {
/// <summary> private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
/// Сервис для фонового выполнения работы private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2);
/// </summary> private readonly IServiceProvider serviceProvider;
public class BackgroundWorker : BackgroundService
public WorkStore WorkStore { get; } = new WorkStore();
public Work? CurrentWork;
public BackgroundWorker(IServiceProvider serviceProvider)
{ {
private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10); this.serviceProvider = serviceProvider;
private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2); }
private readonly IServiceProvider serviceProvider;
private readonly WorkStore workQueue = new WorkStore();
public string? CurrentWorkId;
public BackgroundWorker(IServiceProvider serviceProvider) protected override async Task ExecuteAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{ {
this.serviceProvider = serviceProvider; var work = WorkStore.GetNext();
} if (work is null)
/// <summary>
/// Добавление задачи в очередь.
/// Не периодические задачи будут выполняться вперед.
/// </summary>
/// <param name="work"></param>
/// <exception cref="ArgumentException">Id mast be unique</exception>
public void Push(WorkBase work)
{
workQueue.Push(work);
}
/// <summary>
/// Проверяет наличие работы с указанным Id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool Contains(string id)
{
return workQueue.Contains(id);
}
/// <summary>
/// Удаление работы по ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool Delete(string id)
{
return workQueue.Delete(id);
}
protected override async Task ExecuteAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{ {
var work = workQueue.Pop(); await Task.Delay(executePeriod, token);
if (work is null) continue;
{
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);
} }
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);
} }
} }
} }

View File

@ -1,4 +1,5 @@
using System; using AsbCloudApp.Data;
using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -8,9 +9,9 @@ namespace AsbCloudInfrastructure.Background
/// Класс разовой работы. /// Класс разовой работы.
/// Разовая работа приоритетнее периодической. /// Разовая работа приоритетнее периодической.
/// </summary> /// </summary>
public class WorkBase : BackgroudWorkDto public class Work : BackgroudWorkDto
{ {
internal Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> ActionAsync { get; } private Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> ActionAsync { get; }
/// <summary> /// <summary>
/// Делегат обработки ошибки. /// Делегат обработки ошибки.
@ -48,7 +49,7 @@ namespace AsbCloudInfrastructure.Background
/// </list> /// </list>
/// </para> /// </para>
/// </param> /// </param>
public WorkBase(string id, Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> actionAsync) public Work(string id, Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> actionAsync)
{ {
Id = id; Id = id;
ActionAsync = actionAsync; ActionAsync = actionAsync;
@ -67,7 +68,7 @@ namespace AsbCloudInfrastructure.Background
{ {
var task = ActionAsync(Id, services, UpdateStatus, token); var task = ActionAsync(Id, services, UpdateStatus, token);
await task.WaitAsync(Timeout, token); await task.WaitAsync(Timeout, token);
SetStatusComplete(task.Status); SetStatusComplete();
return true; return true;
} }
catch (Exception exception) catch (Exception exception)

View File

@ -1,45 +1,42 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background namespace AsbCloudInfrastructure.Background;
/// <summary>
/// Класс периодической работы.
/// </summary>
public class WorkPeriodic
{ {
public Work Work { get; }
/// <summary> /// <summary>
/// Класс периодической работы. /// Период выполнения задачи
/// </summary> /// </summary>
public class WorkPeriodic : WorkBase public TimeSpan Period { get; set; }
/// <summary>
/// Время следующего запуска
/// </summary>
public DateTime NextStart
{ {
/// <summary> get
/// Период выполнения задачи
/// </summary>
public TimeSpan Period { get; set; }
/// <summary>
/// Время следующего запуска
/// </summary>
public DateTime NextStart
{ {
get var lastStart = Work.LastComplete?.Start ?? DateTime.MinValue;
{ if (Work.LastError?.Start > lastStart)
var lastStart = LastComplete?.Start ?? DateTime.MinValue; lastStart = Work.LastError.Start;
if (LastError?.Start > lastStart) return lastStart + Period;
lastStart = LastError.Start;
return lastStart + Period;
}
}
/// <summary>
/// Класс периодической работы
/// </summary>
/// <param name="id">Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки</param>
/// <param name="actionAsync">Делегат работы</param>
/// <param name="period">Период выполнения задачи</param>
public WorkPeriodic(string id, Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> actionAsync, TimeSpan period)
: base(id, actionAsync)
{
Period = period;
} }
} }
/// <summary>
/// Класс периодической работы
/// </summary>
/// <param name="id">Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки</param>
/// <param name="actionAsync">Делегат работы</param>
/// <param name="period">Период выполнения задачи</param>
public WorkPeriodic(Work work, TimeSpan period)
{
Work = work;
Period = period;
}
} }

View File

@ -2,118 +2,85 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace AsbCloudInfrastructure.Background namespace AsbCloudInfrastructure.Background;
/// <summary>
/// <para>
/// Очередь работ
/// </para>
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
/// </summary>
public class WorkStore
{ {
private readonly List<WorkPeriodic> periodics = new(8);
/// <summary> /// <summary>
/// <para> /// Список периодических задач
/// Очередь работ
/// </para>
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
/// </summary> /// </summary>
class WorkStore public IEnumerable<WorkPeriodic> Periodics => periodics;
/// <summary>
/// Работы выполняемые один раз
/// </summary>
public Queue<Work> RunOnceQueue { get; private set; } = new(8);
/// <summary>
/// Завершывшиеся с ошибкой
/// </summary>
public CyclycArray<Work> Falled { get; } = new(16);
public void AddPeriodic(Work work, TimeSpan period)
{ {
private readonly List<WorkPeriodic> Periodic = new(8); var periodic = new WorkPeriodic(work, period);
periodics.Add(periodic);
/// <summary>
/// Работы выполняемые один раз
/// </summary>
public Queue<WorkBase> RunOnceQueue { get; } = new(8);
/// <summary>
/// Работы выполняемые периодически
/// </summary>
public IOrderedEnumerable<WorkPeriodic> Periodics => Periodic.OrderBy(work => work.NextStart);
/// <summary>
/// Завершывшиеся с ошибкой
/// </summary>
public CyclycArray<WorkBase> Falled { get; } = new(16);
/// <summary>
/// Добавление работы.
/// </summary>
/// <param name="work"></param>
/// <exception cref="ArgumentException">Id mast be unique</exception>
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);
}
/// <summary>
/// Удаление работы по ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
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<WorkBase>(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;
}
/// <summary>
/// <para>
/// Возвращает приоритетную задачу.
/// </para>
/// <para>
/// Если приоритетные закончились, то ищет ближайшую периодическую.
/// Если до старта ближайшей периодической работы меньше 20 сек,
/// то этой задаче устанавливается время последнего запуска в now и она возвращается.
/// Если больше 20 сек, то возвращается null.
/// </para>
/// </summary>
/// <param name="maxTimeToNextWork"></param>
/// <returns></returns>
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;
}
} }
/// <summary>
/// Удаление работы по ID из одноразовой очереди
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool TryRemoveFromRunOnceQueue(string id)
{
var work = RunOnceQueue.FirstOrDefault(w => w.Id == id);
if (work is not null)
{
RunOnceQueue = new Queue<Work>(RunOnceQueue.Where(w => w.Id != id));
return true;
}
return false;
}
/// <summary>
/// <para>
/// Возвращает приоритетную задачу.
/// </para>
/// <para>
/// Если приоритетные закончились, то ищет ближайшую периодическую.
/// Если до старта ближайшей периодической работы меньше 20 сек,
/// то этой задаче устанавливается время последнего запуска в now и она возвращается.
/// Если больше 20 сек, то возвращается null.
/// </para>
/// </summary>
/// <param name="maxTimeToNextWork"></param>
/// <returns></returns>
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;
}
} }

View File

@ -16,7 +16,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
public static class OperationDetectionWorkFactory public static class OperationDetectionWorkFactory
{ {
private const string workId = "Operation detection"; private const string workId = "Operation detection";
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
private static string progress = "no progress"; private static string progress = "no progress";
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[] private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
@ -32,18 +31,16 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
//new DetectorTemplatingWhileDrilling(), //new DetectorTemplatingWhileDrilling(),
}; };
public static WorkPeriodic MakeWork() public static Work MakeWork() => new Work(workId, WorkAction)
{
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod);
workPeriodic.Timeout = TimeSpan.FromSeconds(15 * 60);
workPeriodic.OnErrorAsync = (id, exception, token) =>
{ {
var text = $"work {id}, when {progress}, throw error:{exception.Message}"; Timeout = TimeSpan.FromMinutes(20),
Trace.TraceWarning(text); OnErrorAsync = (id, exception, token) =>
return Task.CompletedTask; {
var text = $"work {id}, when {progress}, throw error:{exception.Message}";
Trace.TraceWarning(text);
return Task.CompletedTask;
}
}; };
return workPeriodic;
}
// TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД. // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token) private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token)

View File

@ -513,7 +513,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
if (state.IdState == idStateCreating) if (state.IdState == idStateCreating)
{ {
var workId = MakeWorkId(idWell); 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 well = (await wellService.GetOrDefaultAsync(idWell, token))!;
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.pdf"; var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.pdf";
@ -540,12 +540,12 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
return Task.CompletedTask; return Task.CompletedTask;
}; };
var work = new WorkBase(workId, workAction) var work = new Work(workId, workAction)
{ {
OnErrorAsync = onErrorAction OnErrorAsync = onErrorAction
}; };
backgroundWorker.Push(work); backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
} }
} }
} }
@ -559,7 +559,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
private async Task<int> RemoveDrillingProgramAsync(int idWell, CancellationToken token) private async Task<int> RemoveDrillingProgramAsync(int idWell, CancellationToken token)
{ {
var workId = MakeWorkId(idWell); var workId = MakeWorkId(idWell);
backgroundWorker.Delete(workId); backgroundWorker.WorkStore.TryRemoveFromRunOnceQueue(workId);
var filesIds = await context.Files var filesIds = await context.Files
.Where(f => f.IdWell == idWell && .Where(f => f.IdWell == idWell &&

View File

@ -52,12 +52,12 @@ namespace AsbCloudInfrastructure.Services.Email
} }
var workId = MakeWorkId(notification.IdUser, notification.Title, notification.Message); 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 workAction = MakeEmailSendWorkAction(notification);
var work = new WorkBase(workId, workAction); var work = new Work(workId, workAction);
backgroundWorker.Push(work); backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
} }
return Task.CompletedTask; return Task.CompletedTask;

View File

@ -16,16 +16,11 @@ namespace AsbCloudInfrastructure.Services
internal static class LimitingParameterCalcWorkFactory internal static class LimitingParameterCalcWorkFactory
{ {
private const string workId = "Limiting parameter calc"; private const string workId = "Limiting parameter calc";
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
public static WorkPeriodic MakeWork() public static Work MakeWork() => new Work(workId, WorkAction)
{
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod)
{ {
Timeout = TimeSpan.FromMinutes(30) Timeout = TimeSpan.FromMinutes(30)
}; };
return workPeriodic;
}
// TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД. // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token) private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token)

View File

@ -94,8 +94,8 @@ namespace AsbCloudInfrastructure.Services
context.SaveChanges(); context.SaveChanges();
}; };
var work = new WorkBase(workId, workAction); var work = new Work(workId, workAction);
backgroundWorkerService.Push(work); backgroundWorkerService.WorkStore.RunOnceQueue.Enqueue(work);
progressHandler.Invoke(new ReportProgressDto progressHandler.Invoke(new ReportProgressDto
{ {

View File

@ -48,12 +48,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
instance = new TelemetryDataCache<TDto>(); instance = new TelemetryDataCache<TDto>();
var worker = provider.GetRequiredService<BackgroundWorker>(); var worker = provider.GetRequiredService<BackgroundWorker>();
var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; 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<IAsbCloudDbContext>(); var db = provider.GetRequiredService<IAsbCloudDbContext>();
await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token); await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token);
}); });
worker.Push(work); worker.WorkStore.RunOnceQueue.Enqueue(work);
} }
instance.provider = provider; instance.provider = provider;
return instance; return instance;
@ -168,7 +168,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
.Where(well => well.IdTelemetry != null) .Where(well => well.IdTelemetry != null)
.ToArrayAsync(token); .ToArrayAsync(token);
var count = wells.Count(); var count = wells.Length;
var i = 0; var i = 0;
foreach (Well well in wells) foreach (Well well in wells)
{ {

View File

@ -18,7 +18,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems
internal static class SubsystemOperationTimeCalcWorkFactory internal static class SubsystemOperationTimeCalcWorkFactory
{ {
private const string workId = "Subsystem operation time calc"; private const string workId = "Subsystem operation time calc";
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
private const int idSubsytemTorqueMaster = 65537; private const int idSubsytemTorqueMaster = 65537;
private const int idSubsytemSpinMaster = 65536; private const int idSubsytemSpinMaster = 65536;
@ -26,14 +25,10 @@ namespace AsbCloudInfrastructure.Services.Subsystems
private const int idSubsystemAPDSlide = 12; private const int idSubsystemAPDSlide = 12;
private const int idSubsytemMse = 2; private const int idSubsytemMse = 2;
public static WorkPeriodic MakeWork() public static Work MakeWork() => new Work(workId, WorkAction)
{ {
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod) Timeout = TimeSpan.FromMinutes(20)
{ };
Timeout = TimeSpan.FromMinutes(30)
};
return workPeriodic;
}
// TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД. // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token) private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token)

View File

@ -29,7 +29,6 @@ namespace AsbCloudInfrastructure.Services
} }
private const string workId = "Well statistics update"; private const string workId = "Well statistics update";
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache; private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache;
private readonly TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache; private readonly TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache;
@ -53,14 +52,10 @@ namespace AsbCloudInfrastructure.Services
this.gtrRepository = gtrRepository; this.gtrRepository = gtrRepository;
} }
public static WorkPeriodic MakeWork() public static Work MakeWork() => new Work(workId, WorkAction)
{ {
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod) Timeout = TimeSpan.FromMinutes(20)
{ };
Timeout = TimeSpan.FromMinutes(30)
};
return workPeriodic;
}
private static async Task WorkAction(string workName, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token) private static async Task WorkAction(string workName, IServiceProvider serviceProvider, Action<string, double?> onProgress, CancellationToken token)
{ {

View File

@ -15,7 +15,6 @@ using AsbCloudInfrastructure.Services.SAUB;
namespace AsbCloudInfrastructure namespace AsbCloudInfrastructure
{ {
public class Startup public class Startup
{ {
public static void BeforeRunHandler(IHost host) public static void BeforeRunHandler(IHost host)
@ -32,11 +31,11 @@ namespace AsbCloudInfrastructure
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSpinDto>>(); _ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSpinDto>>();
var backgroundWorker = provider.GetRequiredService<BackgroundWorker>(); var backgroundWorker = provider.GetRequiredService<BackgroundWorker>();
backgroundWorker.Push(WellInfoService.MakeWork()); backgroundWorker.WorkStore.AddPeriodic(WellInfoService.MakeWork(), TimeSpan.FromMinutes(30));
backgroundWorker.Push(OperationDetectionWorkFactory.MakeWork()); backgroundWorker.WorkStore.AddPeriodic(OperationDetectionWorkFactory.MakeWork(), TimeSpan.FromMinutes(15));
backgroundWorker.Push(SubsystemOperationTimeCalcWorkFactory.MakeWork()); backgroundWorker.WorkStore.AddPeriodic(SubsystemOperationTimeCalcWorkFactory.MakeWork(), TimeSpan.FromMinutes(30));
backgroundWorker.Push(LimitingParameterCalcWorkFactory.MakeWork()); backgroundWorker.WorkStore.AddPeriodic(LimitingParameterCalcWorkFactory.MakeWork(), TimeSpan.FromMinutes(30));
backgroundWorker.Push(MakeMemoryMonitoringWork()); backgroundWorker.WorkStore.AddPeriodic(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>(); var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>();
@ -48,17 +47,15 @@ namespace AsbCloudInfrastructure
}); });
} }
static WorkPeriodic MakeMemoryMonitoringWork() static Work MakeMemoryMonitoringWork()
{ {
var workId = "Memory monitoring";
var workAction = (string _, IServiceProvider _, Action<string, double?> _, CancellationToken _) => { var workAction = (string _, IServiceProvider _, Action<string, double?> _, CancellationToken _) => {
var bytes = GC.GetTotalMemory(false); var bytes = GC.GetTotalMemory(false);
var bytesString = FromatBytes(bytes); var bytesString = FromatBytes(bytes);
System.Diagnostics.Trace.TraceInformation($"Total memory allocated is {bytesString} bytes. DbContext count is:{AsbCloudDbContext.ReferenceCount}"); System.Diagnostics.Trace.TraceInformation($"Total memory allocated is {bytesString} bytes. DbContext count is:{AsbCloudDbContext.ReferenceCount}");
return Task.CompletedTask; return Task.CompletedTask;
}; };
var workPeriod = TimeSpan.FromMinutes(1); var work = new Work("Memory monitoring", workAction);
var work = new WorkPeriodic(workId, workAction, workPeriod);
return work; return work;
} }

View File

@ -366,7 +366,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None); var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
Assert.Equal(2, state.IdState); Assert.Equal(2, state.IdState);
backgroundWorkerMock.Verify(s => s.Push(It.IsAny<WorkBase>())); backgroundWorkerMock.Verify(s => s.Push(It.IsAny<Work>()));
} }
[Fact] [Fact]

View File

@ -29,12 +29,12 @@ public class SignalRNotificationTransportService : INotificationTransportService
{ {
var workId = HashCode.Combine(notifications.Select(n => n.Id)).ToString("x"); 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; return Task.CompletedTask;
var workAction = MakeSignalRSendWorkAction(notifications); var workAction = MakeSignalRSendWorkAction(notifications);
var work = new WorkBase(workId, workAction); var work = new Work(workId, workAction);
backgroundWorker.Push(work); backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
return Task.CompletedTask; return Task.CompletedTask;
} }