forked from ddrilling/AsbCloudServer
Merge branch 'BackgroundWorker' into dev
This commit is contained in:
commit
71c2a3241e
@ -172,7 +172,7 @@ namespace AsbCloudApp.Data
|
|||||||
if (progress.HasValue)
|
if (progress.HasValue)
|
||||||
CurrentState.Progress = progress.Value;
|
CurrentState.Progress = progress.Value;
|
||||||
|
|
||||||
Trace.TraceInformation($"{WorkNameForTrace} state: {newState} [{100*progress:#}%]");
|
Trace.TraceInformation($"{WorkNameForTrace} state[{100*progress:#}%]: {newState}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -12,13 +14,37 @@ namespace AsbCloudInfrastructure.Background;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class BackgroundWorker : BackgroundService
|
public class BackgroundWorker : BackgroundService
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
|
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
|
||||||
private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2);
|
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
public WorkStore WorkStore { get; } = new WorkStore();
|
/// <summary>
|
||||||
|
/// Очередь работ
|
||||||
|
/// </summary>
|
||||||
|
private Queue<Work> works = new(8);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Список периодических работ
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Work> Works => works;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа выполняемая в данный момент
|
||||||
|
/// </summary>
|
||||||
public Work? CurrentWork;
|
public Work? CurrentWork;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// последние 16 завершившиеся с ошибкой
|
||||||
|
/// </summary>
|
||||||
|
public CyclycArray<Work> Felled { get; } = new(16);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// последние 16 успешно завершенных
|
||||||
|
/// </summary>
|
||||||
|
public CyclycArray<Work> Done { get; } = new(16);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ошибка в главном цикле, никогда не должна появляться
|
||||||
|
/// </summary>
|
||||||
public string MainLoopLastException { get; private set; } = string.Empty;
|
public string MainLoopLastException { get; private set; } = string.Empty;
|
||||||
|
|
||||||
public BackgroundWorker(IServiceProvider serviceProvider)
|
public BackgroundWorker(IServiceProvider serviceProvider)
|
||||||
@ -28,26 +54,18 @@ public class BackgroundWorker : BackgroundService
|
|||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken token)
|
protected override async Task ExecuteAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
while (!token.IsCancellationRequested)
|
while (!token.IsCancellationRequested && works.TryDequeue(out CurrentWork))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var work = WorkStore.GetNext();
|
|
||||||
if (work is null)
|
|
||||||
{
|
|
||||||
await Task.Delay(executePeriod, token);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentWork = work;
|
|
||||||
using var scope = serviceProvider.CreateScope();
|
using var scope = serviceProvider.CreateScope();
|
||||||
|
|
||||||
var result = await work.Start(scope.ServiceProvider, token);
|
var result = await CurrentWork.Start(scope.ServiceProvider, token);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
WorkStore.Felled.Add(work);
|
Felled.Add(CurrentWork);
|
||||||
else
|
else
|
||||||
WorkStore.Done.Add(work);
|
Done.Add(CurrentWork);
|
||||||
|
|
||||||
CurrentWork = null;
|
CurrentWork = null;
|
||||||
await Task.Delay(minDelay, token);
|
await Task.Delay(minDelay, token);
|
||||||
@ -64,4 +82,36 @@ public class BackgroundWorker : BackgroundService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в очередь
|
||||||
|
/// <para>
|
||||||
|
/// work.Id может быть не уникальным,
|
||||||
|
/// при этом метод TryRemoveFromQueue удалит все работы с совпадающими id
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="work"></param>
|
||||||
|
public void Enqueue(Work work)
|
||||||
|
{
|
||||||
|
works.Enqueue(work);
|
||||||
|
if (ExecuteTask is null || ExecuteTask.IsCompleted)
|
||||||
|
StartAsync(CancellationToken.None).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление работы по ID из одноразовой очереди
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool TryRemoveFromQueue(string id)
|
||||||
|
{
|
||||||
|
var work = Works.FirstOrDefault(w => w.Id == id);
|
||||||
|
if (work is not null)
|
||||||
|
{
|
||||||
|
works = new Queue<Work>(Works.Where(w => w.Id != id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
115
AsbCloudInfrastructure/Background/PeriodicBackgroundWorker.cs
Normal file
115
AsbCloudInfrastructure/Background/PeriodicBackgroundWorker.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Background;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для фонового выполнения периодической работы
|
||||||
|
/// </summary>
|
||||||
|
public class PeriodicBackgroundWorker : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
|
||||||
|
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
|
||||||
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
|
private readonly List<WorkPeriodic> works = new(8);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Список периодических работ
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<WorkPeriodic> Works => works;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа выполняемая в данный момент
|
||||||
|
/// </summary>
|
||||||
|
public Work? CurrentWork;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ошибка в главном цикле, никогда не должна появляться
|
||||||
|
/// </summary>
|
||||||
|
public string MainLoopLastException { get; private set; } = string.Empty;
|
||||||
|
|
||||||
|
public PeriodicBackgroundWorker(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
this.serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var periodicWork = GetNext();
|
||||||
|
if (periodicWork is null)
|
||||||
|
{
|
||||||
|
await Task.Delay(executePeriod, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentWork = periodicWork.Work;
|
||||||
|
|
||||||
|
using var scope = serviceProvider.CreateScope();
|
||||||
|
|
||||||
|
var result = await periodicWork.Work.Start(scope.ServiceProvider, token);
|
||||||
|
|
||||||
|
CurrentWork = null;
|
||||||
|
await Task.Delay(minDelay, token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MainLoopLastException = $"BackgroundWorker " +
|
||||||
|
$"MainLoopLastException: \r\n" +
|
||||||
|
$"date: {DateTime.Now:O}\r\n" +
|
||||||
|
$"message: {ex.Message}\r\n" +
|
||||||
|
$"inner: {ex.InnerException?.Message}\r\n" +
|
||||||
|
$"stackTrace: {ex.StackTrace}";
|
||||||
|
Trace.TraceError(MainLoopLastException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="period"></param>
|
||||||
|
public void Add<T>(TimeSpan period)
|
||||||
|
where T : Work, new()
|
||||||
|
{
|
||||||
|
var work = new T();
|
||||||
|
var periodic = new WorkPeriodic(work, period);
|
||||||
|
works.Add(periodic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="work"></param>
|
||||||
|
/// <param name="period"></param>
|
||||||
|
public void Add(Work work, TimeSpan period)
|
||||||
|
{
|
||||||
|
var periodic = new WorkPeriodic(work, period);
|
||||||
|
works.Add(periodic);
|
||||||
|
if (ExecuteTask is null || ExecuteTask.IsCompleted)
|
||||||
|
StartAsync(CancellationToken.None).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private WorkPeriodic? GetNext()
|
||||||
|
{
|
||||||
|
var work = works
|
||||||
|
.OrderBy(w => w.NextStart)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (work is null || work.NextStart > DateTime.Now)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return work;
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,8 @@ namespace AsbCloudInfrastructure.Background;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Work : BackgroundWorkDto
|
public abstract class Work : BackgroundWorkDto
|
||||||
{
|
{
|
||||||
|
private CancellationTokenSource? stoppingCts;
|
||||||
|
|
||||||
private sealed class WorkBase : Work
|
private sealed class WorkBase : Work
|
||||||
{
|
{
|
||||||
private Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> ActionAsync { get; }
|
private Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> ActionAsync { get; }
|
||||||
@ -69,8 +71,9 @@ public abstract class Work : BackgroundWorkDto
|
|||||||
SetStatusStart();
|
SetStatusStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var task = Action(Id, services, UpdateStatus, token);
|
stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(token);
|
||||||
await task.WaitAsync(Timeout, token);
|
var task = Action(Id, services, UpdateStatus, stoppingCts.Token);
|
||||||
|
await task.WaitAsync(Timeout, stoppingCts.Token);
|
||||||
SetStatusComplete();
|
SetStatusComplete();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -97,6 +100,11 @@ public abstract class Work : BackgroundWorkDto
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
stoppingCts?.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatExceptionMessage(Exception exception)
|
private static string FormatExceptionMessage(Exception exception)
|
||||||
{
|
{
|
||||||
var firstException = FirstException(exception);
|
var firstException = FirstException(exception);
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Background;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>
|
|
||||||
/// Очередь работ
|
|
||||||
/// </para>
|
|
||||||
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
|
|
||||||
/// </summary>
|
|
||||||
public class WorkStore
|
|
||||||
{
|
|
||||||
private readonly List<WorkPeriodic> periodics = new(8);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Список периодических задач
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<WorkPeriodic> Periodics => periodics;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Работы выполняемые один раз
|
|
||||||
/// </summary>
|
|
||||||
public Queue<Work> RunOnceQueue { get; private set; } = new(8);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// последние 16 завершившиеся с ошибкой
|
|
||||||
/// </summary>
|
|
||||||
public CyclycArray<Work> Felled { get; } = new(16);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// последние 16 успешно завершенных
|
|
||||||
/// </summary>
|
|
||||||
public CyclycArray<Work> Done { get; } = new(16);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="period"></param>
|
|
||||||
public void AddPeriodic<T>(TimeSpan period)
|
|
||||||
where T : Work, new()
|
|
||||||
{
|
|
||||||
var work = new T();
|
|
||||||
var periodic = new WorkPeriodic(work, period);
|
|
||||||
periodics.Add(periodic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="work"></param>
|
|
||||||
/// <param name="period"></param>
|
|
||||||
public void AddPeriodic(Work work, TimeSpan period)
|
|
||||||
{
|
|
||||||
var periodic = new WorkPeriodic(work, period);
|
|
||||||
periodics.Add(periodic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -165,6 +165,7 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddSingleton<ITelemetryDataCache<TelemetryDataSaubDto>>(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
|
services.AddSingleton<ITelemetryDataCache<TelemetryDataSaubDto>>(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
|
||||||
services.AddSingleton<ITelemetryDataCache<TelemetryDataSpinDto>>(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
|
services.AddSingleton<ITelemetryDataCache<TelemetryDataSpinDto>>(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
|
||||||
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
||||||
|
services.AddSingleton<PeriodicBackgroundWorker>();
|
||||||
services.AddSingleton<BackgroundWorker>();
|
services.AddSingleton<BackgroundWorker>();
|
||||||
services.AddSingleton<NotificationBackgroundWorker>();
|
services.AddSingleton<NotificationBackgroundWorker>();
|
||||||
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
||||||
|
@ -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.WorkStore.RunOnceQueue.Any(w => w.Id == workId))
|
if (!backgroundWorker.Works.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";
|
||||||
@ -542,7 +542,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
|
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
work.OnErrorAsync = onErrorAction;
|
work.OnErrorAsync = onErrorAction;
|
||||||
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorker.Enqueue(work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,7 +556,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.WorkStore.TryRemoveFromRunOnceQueue(workId);
|
backgroundWorker.TryRemoveFromQueue(workId);
|
||||||
|
|
||||||
var filesIds = await context.Files
|
var filesIds = await context.Files
|
||||||
.Where(f => f.IdWell == idWell &&
|
.Where(f => f.IdWell == idWell &&
|
||||||
|
@ -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.WorkStore.RunOnceQueue.Any(w=>w.Id==workId))
|
if (!backgroundWorker.Works.Any(w=>w.Id==workId))
|
||||||
{
|
{
|
||||||
var workAction = MakeEmailSendWorkAction(notification);
|
var workAction = MakeEmailSendWorkAction(notification);
|
||||||
|
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorker.Enqueue(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
@ -95,7 +95,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
};
|
};
|
||||||
|
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
backgroundWorkerService.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorkerService.Enqueue(work);
|
||||||
|
|
||||||
progressHandler.Invoke(new ReportProgressDto
|
progressHandler.Invoke(new ReportProgressDto
|
||||||
{
|
{
|
||||||
|
@ -52,7 +52,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token);
|
await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token);
|
||||||
});
|
});
|
||||||
work.Timeout = TimeSpan.FromMinutes(15);
|
work.Timeout = TimeSpan.FromMinutes(15);
|
||||||
worker.WorkStore.RunOnceQueue.Enqueue(work);
|
worker.Enqueue(work);
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,12 @@ namespace AsbCloudInfrastructure
|
|||||||
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
||||||
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSpinDto>>();
|
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSpinDto>>();
|
||||||
|
|
||||||
var backgroundWorker = provider.GetRequiredService<BackgroundWorker>();
|
var backgroundWorker = provider.GetRequiredService<PeriodicBackgroundWorker>();
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));
|
backgroundWorker.Add<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WorkOperationDetection>(TimeSpan.FromMinutes(15));
|
backgroundWorker.Add<WorkOperationDetection>(TimeSpan.FromMinutes(15));
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WorkSubsystemOperationTimeCalc>(TimeSpan.FromMinutes(30));
|
backgroundWorker.Add<WorkSubsystemOperationTimeCalc>(TimeSpan.FromMinutes(30));
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WorkLimitingParameterCalc>(TimeSpan.FromMinutes(30));
|
backgroundWorker.Add<WorkLimitingParameterCalc>(TimeSpan.FromMinutes(30));
|
||||||
backgroundWorker.WorkStore.AddPeriodic(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
|
backgroundWorker.Add(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>();
|
var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>();
|
||||||
|
|
||||||
|
@ -53,11 +53,21 @@ namespace AsbCloudWebApi.Tests.Middlware
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DatesRangeDto? GetRange(int idWell)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset start, DateTimeOffset end, CancellationToken token)
|
public Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset start, DateTimeOffset end, CancellationToken token)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token) => throw new NotImplementedException();
|
public Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token) => throw new NotImplementedException();
|
||||||
|
|
||||||
public Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
|
public Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
|
||||||
|
113
AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs
Normal file
113
AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NSubstitute;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services;
|
||||||
|
|
||||||
|
public class BackgroundWorkerTest
|
||||||
|
{
|
||||||
|
private IServiceProvider provider;
|
||||||
|
private BackgroundWorker service;
|
||||||
|
|
||||||
|
public BackgroundWorkerTest()
|
||||||
|
{
|
||||||
|
provider = Substitute.For<IServiceProvider, ISupportRequiredService>();
|
||||||
|
var serviceScope = Substitute.For<IServiceScope>();
|
||||||
|
var serviceScopeFactory = Substitute.For<IServiceScopeFactory>();
|
||||||
|
serviceScopeFactory.CreateScope().Returns(serviceScope);
|
||||||
|
((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory);
|
||||||
|
|
||||||
|
service = new BackgroundWorker(provider);
|
||||||
|
typeof(BackgroundWorker)
|
||||||
|
.GetField("minDelay", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
|
.SetValue(service, TimeSpan.FromMilliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Enqueue_n_works()
|
||||||
|
{
|
||||||
|
var workCount = 10;
|
||||||
|
var result = 0;
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
return Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//act
|
||||||
|
for (int i = 0; i < workCount; i++)
|
||||||
|
{
|
||||||
|
var work = Work.CreateByDelegate(i.ToString(), workAction);
|
||||||
|
service.Enqueue(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
await service.ExecuteTask;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(workCount, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Enqueue_continues_after_exceptions()
|
||||||
|
{
|
||||||
|
var expectadResult = 42;
|
||||||
|
var result = 0;
|
||||||
|
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result = expectadResult;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
var goodWork = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
Task failAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
=> throw new Exception();
|
||||||
|
|
||||||
|
var badWork = Work.CreateByDelegate("", failAction);
|
||||||
|
badWork.OnErrorAsync = (id, exception, token) => throw new Exception();
|
||||||
|
|
||||||
|
//act
|
||||||
|
service.Enqueue(badWork);
|
||||||
|
service.Enqueue(goodWork);
|
||||||
|
|
||||||
|
await service.ExecuteTask;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(expectadResult, result);
|
||||||
|
Assert.Equal(1, service.Felled.Count);
|
||||||
|
Assert.Equal(1, service.Done.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryRemove()
|
||||||
|
{
|
||||||
|
var workCount = 5;
|
||||||
|
var result = 0;
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
return Task.Delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//act
|
||||||
|
for (int i = 0; i < workCount; i++)
|
||||||
|
{
|
||||||
|
var work = Work.CreateByDelegate(i.ToString(), workAction);
|
||||||
|
service.Enqueue(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
var removed = service.TryRemoveFromQueue((workCount - 1).ToString());
|
||||||
|
|
||||||
|
await service.ExecuteTask;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.True(removed);
|
||||||
|
Assert.Equal(workCount - 1, result);
|
||||||
|
Assert.Equal(workCount - 1, service.Done.Count);
|
||||||
|
}
|
||||||
|
}
|
@ -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.WorkStore.RunOnceQueue.Enqueue(It.IsAny<Work>()));
|
backgroundWorkerMock.Verify(s => s.Enqueue(It.IsAny<Work>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
@ -0,0 +1,97 @@
|
|||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using DocumentFormat.OpenXml.Drawing.Charts;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NSubstitute;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services;
|
||||||
|
|
||||||
|
public class PeriodicBackgroundWorkerTest
|
||||||
|
{
|
||||||
|
private IServiceProvider provider;
|
||||||
|
private PeriodicBackgroundWorker service;
|
||||||
|
|
||||||
|
public PeriodicBackgroundWorkerTest()
|
||||||
|
{
|
||||||
|
provider = Substitute.For<IServiceProvider, ISupportRequiredService>();
|
||||||
|
var serviceScope = Substitute.For<IServiceScope>();
|
||||||
|
var serviceScopeFactory = Substitute.For<IServiceScopeFactory>();
|
||||||
|
serviceScopeFactory.CreateScope().Returns(serviceScope);
|
||||||
|
((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory);
|
||||||
|
|
||||||
|
service = new PeriodicBackgroundWorker(provider);
|
||||||
|
typeof(PeriodicBackgroundWorker)
|
||||||
|
.GetField("minDelay", BindingFlags.NonPublic | BindingFlags.Instance)?
|
||||||
|
.SetValue(service, TimeSpan.FromMilliseconds(1));
|
||||||
|
|
||||||
|
typeof(PeriodicBackgroundWorker)
|
||||||
|
.GetField("executePeriod", BindingFlags.NonPublic | BindingFlags.Instance)?
|
||||||
|
.SetValue(service, TimeSpan.FromMilliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task WorkRunsTwice()
|
||||||
|
{
|
||||||
|
var workCount = 2;
|
||||||
|
var periodMs = 100d;
|
||||||
|
|
||||||
|
var period = TimeSpan.FromMilliseconds(periodMs);
|
||||||
|
|
||||||
|
var result = 0;
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
//act
|
||||||
|
var work = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
var stopwatch = Stopwatch.StartNew();
|
||||||
|
service.Add(work, period);
|
||||||
|
|
||||||
|
var delay = (periodMs / 20) + (periodMs * workCount) - stopwatch.ElapsedMilliseconds;
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(delay));
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(workCount, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Enqueue_continues_after_exceptions()
|
||||||
|
{
|
||||||
|
var expectadResult = 42;
|
||||||
|
var result = 0;
|
||||||
|
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result = expectadResult;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
var goodWork = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
Task failAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
=> throw new Exception();
|
||||||
|
|
||||||
|
var badWork = Work.CreateByDelegate("", failAction);
|
||||||
|
badWork.OnErrorAsync = (id, exception, token) => throw new Exception();
|
||||||
|
|
||||||
|
//act
|
||||||
|
service.Add(badWork, TimeSpan.FromSeconds(2));
|
||||||
|
service.Add(goodWork, TimeSpan.FromSeconds(2));
|
||||||
|
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(20));
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(expectadResult, result);
|
||||||
|
Assert.Equal(1, badWork.CountErrors);
|
||||||
|
Assert.Equal(1, goodWork.CountComplete);
|
||||||
|
Assert.Equal(1, goodWork.CountStart);
|
||||||
|
}
|
||||||
|
}
|
126
AsbCloudWebApi.Tests/Services/WorkTest.cs
Normal file
126
AsbCloudWebApi.Tests/Services/WorkTest.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NSubstitute;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services
|
||||||
|
{
|
||||||
|
public class WorkTest
|
||||||
|
{
|
||||||
|
private IServiceProvider provider;
|
||||||
|
|
||||||
|
public WorkTest()
|
||||||
|
{
|
||||||
|
provider = Substitute.For<IServiceProvider, ISupportRequiredService>();
|
||||||
|
var serviceScope = Substitute.For<IServiceScope>();
|
||||||
|
var serviceScopeFactory = Substitute.For<IServiceScopeFactory>();
|
||||||
|
serviceScopeFactory.CreateScope().Returns(serviceScope);
|
||||||
|
((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Work_done_with_success()
|
||||||
|
{
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
=> Task.CompletedTask;
|
||||||
|
|
||||||
|
var work = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var begin = DateTime.Now;
|
||||||
|
await work.Start(provider, CancellationToken.None);
|
||||||
|
var done = DateTime.Now;
|
||||||
|
var executionTime = done - begin;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(1, work.CountComplete);
|
||||||
|
Assert.Equal(1, work.CountStart);
|
||||||
|
Assert.Equal(0, work.CountErrors);
|
||||||
|
Assert.Null(work.CurrentState);
|
||||||
|
Assert.Null(work.LastError);
|
||||||
|
|
||||||
|
var lastState = work.LastComplete;
|
||||||
|
Assert.NotNull(lastState);
|
||||||
|
Assert.InRange(lastState.Start, begin, done - 0.5 * executionTime);
|
||||||
|
Assert.InRange(lastState.End, done - 0.5 * executionTime, done);
|
||||||
|
Assert.InRange(lastState.ExecutionTime, TimeSpan.Zero, executionTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Work_calls_callback()
|
||||||
|
{
|
||||||
|
var expectedState = "42";
|
||||||
|
var expectedProgress = 42d;
|
||||||
|
|
||||||
|
var timeout = TimeSpan.FromMilliseconds(40);
|
||||||
|
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
callback.Invoke(expectedState, expectedProgress);
|
||||||
|
return Task.Delay(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
var work = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var begin = DateTime.Now;
|
||||||
|
_ = work.Start(provider, CancellationToken.None);
|
||||||
|
await Task.Delay(timeout/3);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(0, work.CountComplete);
|
||||||
|
Assert.Equal(1, work.CountStart);
|
||||||
|
Assert.Equal(0, work.CountErrors);
|
||||||
|
Assert.NotNull(work.CurrentState);
|
||||||
|
Assert.Null(work.LastComplete);
|
||||||
|
Assert.Null(work.LastError);
|
||||||
|
|
||||||
|
var currentState = work.CurrentState;
|
||||||
|
Assert.NotNull(currentState);
|
||||||
|
Assert.InRange(currentState.Start, begin, begin + timeout);
|
||||||
|
Assert.InRange(currentState.StateUpdate, begin, begin + timeout);
|
||||||
|
Assert.Equal(expectedState, currentState.State);
|
||||||
|
Assert.Equal(expectedProgress, currentState.Progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Work_fails_with_info()
|
||||||
|
{
|
||||||
|
var expectedState = "41";
|
||||||
|
var expectedErrorText = "42";
|
||||||
|
var minWorkTime = TimeSpan.FromMilliseconds(10);
|
||||||
|
|
||||||
|
async Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
await Task.Delay(minWorkTime);
|
||||||
|
callback(expectedState, 0);
|
||||||
|
throw new Exception(expectedErrorText);
|
||||||
|
}
|
||||||
|
|
||||||
|
var work = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var begin = DateTime.Now;
|
||||||
|
await work.Start(provider, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(0, work.CountComplete);
|
||||||
|
Assert.Equal(1, work.CountStart);
|
||||||
|
Assert.Equal(1, work.CountErrors);
|
||||||
|
Assert.Null(work.CurrentState);
|
||||||
|
Assert.Null(work.LastComplete);
|
||||||
|
|
||||||
|
var error = work.LastError;
|
||||||
|
Assert.NotNull(error);
|
||||||
|
Assert.InRange(error.Start, begin, DateTime.Now);
|
||||||
|
Assert.InRange(error.End, begin, DateTime.Now);
|
||||||
|
Assert.InRange(error.ExecutionTime, minWorkTime, DateTime.Now - begin);
|
||||||
|
Assert.Contains(expectedErrorText, error.ErrorText, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
Assert.Equal(expectedState, error.State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,23 +14,22 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class BackgroundWorkController : ControllerBase
|
public class BackgroundWorkController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly BackgroundWorker backgroundWorker;
|
private readonly BackgroundWorker worker;
|
||||||
|
|
||||||
public BackgroundWorkController(BackgroundWorker backgroundWorker)
|
public BackgroundWorkController(BackgroundWorker worker)
|
||||||
{
|
{
|
||||||
this.backgroundWorker = backgroundWorker;
|
this.worker = worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAll()
|
public IActionResult GetAll()
|
||||||
{
|
{
|
||||||
var result = new {
|
var result = new {
|
||||||
CurrentWork = (BackgroundWorkDto?)backgroundWorker.CurrentWork,
|
CurrentWork = (BackgroundWorkDto?)worker.CurrentWork,
|
||||||
backgroundWorker.MainLoopLastException,
|
worker.MainLoopLastException,
|
||||||
RunOnceQueue = backgroundWorker.WorkStore.RunOnceQueue.Select(work => (BackgroundWorkDto)work),
|
RunOnceQueue = worker.Works.Select(work => (BackgroundWorkDto)work),
|
||||||
Periodics = backgroundWorker.WorkStore.Periodics.Select(work => (BackgroundWorkDto)work.Work),
|
Done = worker.Done.Select(work => (BackgroundWorkDto)work),
|
||||||
Done = backgroundWorker.WorkStore.Done.Select(work => (BackgroundWorkDto)work),
|
Felled = worker.Felled.Select(work => (BackgroundWorkDto)work),
|
||||||
Felled = backgroundWorker.WorkStore.Felled.Select(work => (BackgroundWorkDto)work),
|
|
||||||
};
|
};
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
@ -38,7 +37,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[HttpGet("current")]
|
[HttpGet("current")]
|
||||||
public IActionResult GetCurrent()
|
public IActionResult GetCurrent()
|
||||||
{
|
{
|
||||||
var work = backgroundWorker.CurrentWork;
|
var work = worker.CurrentWork;
|
||||||
if (work == null)
|
if (work == null)
|
||||||
return NoContent();
|
return NoContent();
|
||||||
|
|
||||||
@ -48,22 +47,22 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[HttpGet("failed")]
|
[HttpGet("failed")]
|
||||||
public IActionResult GetFelled()
|
public IActionResult GetFelled()
|
||||||
{
|
{
|
||||||
var result = backgroundWorker.WorkStore.Felled.Select(work => (BackgroundWorkDto)work);
|
var result = worker.Felled.Select(work => (BackgroundWorkDto)work);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("done")]
|
[HttpGet("done")]
|
||||||
public IActionResult GetDone()
|
public IActionResult GetDone()
|
||||||
{
|
{
|
||||||
var result = backgroundWorker.WorkStore.Done.Select(work => (BackgroundWorkDto)work);
|
var result = worker.Done.Select(work => (BackgroundWorkDto)work);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("restart"), Obsolete("temporary method")]
|
[HttpPost("restart"), Obsolete("temporary method")]
|
||||||
public async Task<IActionResult> RestartAsync(CancellationToken token)
|
public async Task<IActionResult> RestartAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
await backgroundWorker.StopAsync(token);
|
await worker.StopAsync(token);
|
||||||
await backgroundWorker.StartAsync(token);
|
await worker.StartAsync(token);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
public class PeriodicBackgroundWorkerController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly PeriodicBackgroundWorker worker;
|
||||||
|
|
||||||
|
public PeriodicBackgroundWorkerController(PeriodicBackgroundWorker worker)
|
||||||
|
{
|
||||||
|
this.worker = worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetAll()
|
||||||
|
{
|
||||||
|
var result = new
|
||||||
|
{
|
||||||
|
currentWork = (BackgroundWorkDto?)worker.CurrentWork,
|
||||||
|
worker.MainLoopLastException,
|
||||||
|
works = worker.Works.Select(work => (BackgroundWorkDto)work.Work),
|
||||||
|
};
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("restart"), Obsolete("temporary method")]
|
||||||
|
public async Task<IActionResult> RestartAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
await worker.StopAsync(token);
|
||||||
|
await worker.StartAsync(token);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ namespace AsbCloudWebApi.SignalR
|
|||||||
await base.AddToGroup(groupName);
|
await base.AddToGroup(groupName);
|
||||||
|
|
||||||
var workId = groupName.Replace("Report_", "");
|
var workId = groupName.Replace("Report_", "");
|
||||||
var work = backgroundWorker.WorkStore.RunOnceQueue.FirstOrDefault(work => work.Id == workId);
|
var work = backgroundWorker.Works.FirstOrDefault(work => work.Id == workId);
|
||||||
|
|
||||||
var progress = new ReportProgressDto()
|
var progress = new ReportProgressDto()
|
||||||
{
|
{
|
||||||
|
@ -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.WorkStore.RunOnceQueue.Any(w => w.Id == workId))
|
if (backgroundWorker.Works.Any(w => w.Id == workId))
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var workAction = MakeSignalRSendWorkAction(notifications);
|
var workAction = MakeSignalRSendWorkAction(notifications);
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorker.Enqueue(work);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user