forked from ddrilling/AsbCloudServer
BackgroundWorker adapt other services to this one.
This commit is contained in:
parent
98c7599c4b
commit
89e0495d09
@ -73,7 +73,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="fileStream"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<FileInfoDto?> SaveAsync(int idWell, int? idUser, int idCategory,
|
||||
public async Task<FileInfoDto> SaveAsync(int idWell, int? idUser, int idCategory,
|
||||
string fileFullName, Stream fileStream, CancellationToken token)
|
||||
{
|
||||
//save info to db
|
||||
@ -93,7 +93,7 @@ namespace AsbCloudApp.Services
|
||||
string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId);
|
||||
await fileStorageRepository.SaveFileAsync(filePath, fileStream, token);
|
||||
|
||||
return await GetOrDefaultAsync(fileId, token);
|
||||
return (await GetOrDefaultAsync(fileId, token))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudApp.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Сервис выстраивает очередь из фоновых задач. Ограничивает количество одновременно выполняющихся задач.
|
||||
/// </summary>
|
||||
public interface IBackgroundWorkerService
|
||||
{
|
||||
/// <summary>
|
||||
/// Проверка, есть ли задача в очереди
|
||||
/// </summary>
|
||||
/// <param name="id">идентификатор задачи</param>
|
||||
/// <returns></returns>
|
||||
bool Contains(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет в очередь задач новую задачу
|
||||
/// </summary>
|
||||
/// <param name="id">идентификатор задачи</param>
|
||||
/// <param name="func">делегат</param>
|
||||
/// <returns>id задачи в очереди</returns>
|
||||
string Enqueue(string id, Func<string, CancellationToken, Task> func);
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет в очередь задач новую задачу
|
||||
/// </summary>
|
||||
/// <param name="func"></param>
|
||||
/// <returns></returns>
|
||||
string Enqueue(Func<string, CancellationToken, Task> func);
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет в очередь задач новую задачу
|
||||
/// </summary>
|
||||
/// <param name="id">идентификатор задачи</param>
|
||||
/// <param name="func"></param>
|
||||
/// <param name="onError"></param>
|
||||
/// <returns></returns>
|
||||
string Enqueue(string id, Func<string, CancellationToken, Task> func, Func<string, Exception, CancellationToken, Task> onError);
|
||||
|
||||
/// <summary>
|
||||
/// Пробуем удалить задачу по идентификатору
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
bool TryRemove(string id);
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@ namespace AsbCloudApp.Services
|
||||
/// </summary>
|
||||
int ReportCategoryId { get; }
|
||||
|
||||
// TODO: rename this method
|
||||
/// <summary>
|
||||
/// Поставить рапорт в очередь на формирование
|
||||
/// </summary>
|
||||
@ -28,7 +27,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="end"></param>
|
||||
/// <param name="handleReportProgress"></param>
|
||||
/// <returns></returns>
|
||||
string CreateReport(int idWell, int idUser, int stepSeconds,
|
||||
string EnqueueCreateReportWork(int idWell, int idUser, int stepSeconds,
|
||||
int format, DateTime begin, DateTime end,
|
||||
Action<object, string> handleReportProgress);
|
||||
|
||||
@ -49,7 +48,7 @@ namespace AsbCloudApp.Services
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <returns></returns>
|
||||
DatesRangeDto GetDatesRangeOrDefault(int idWell);
|
||||
DatesRangeDto? GetDatesRangeOrDefault(int idWell);
|
||||
|
||||
/// <summary>
|
||||
/// Список готовых рапортов
|
||||
|
@ -6,6 +6,7 @@ using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using AsbCloudInfrastructure.Services;
|
||||
using AsbCloudInfrastructure.Services.DailyReport;
|
||||
@ -106,7 +107,7 @@ namespace AsbCloudInfrastructure
|
||||
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
|
||||
services.AddSingleton<ITelemetryTracker, TelemetryTracker>();
|
||||
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
||||
services.AddSingleton<IBackgroundWorkerService, BackgroundWorkerService>();
|
||||
services.AddSingleton<BackgroundWorker>();
|
||||
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
||||
|
||||
services.AddTransient<IAuthService, AuthService>();
|
||||
|
@ -10,7 +10,7 @@ namespace AsbCloudInfrastructure
|
||||
{
|
||||
public class ReportDataSourcePgCloud : IReportDataSource
|
||||
{
|
||||
private readonly AsbCloudDbContext context;
|
||||
private readonly IAsbCloudDbContext context;
|
||||
|
||||
private readonly int? idTelemetry;
|
||||
private readonly WellInfoReport info;
|
||||
@ -25,7 +25,7 @@ namespace AsbCloudInfrastructure
|
||||
{3, "Информация"},
|
||||
};
|
||||
|
||||
public ReportDataSourcePgCloud(AsbCloudDbContext context, int idWell)
|
||||
public ReportDataSourcePgCloud(IAsbCloudDbContext context, int idWell)
|
||||
{
|
||||
this.context = context;
|
||||
|
||||
@ -65,6 +65,7 @@ namespace AsbCloudInfrastructure
|
||||
|
||||
public AnalyzeResult Analyze()
|
||||
{
|
||||
// TODO: Replace by linq methods.
|
||||
var messagesStat = (from item in context.TelemetryMessages
|
||||
where item.IdTelemetry == idTelemetry
|
||||
group item.DateTime by item.IdTelemetry into g
|
||||
|
@ -1,88 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Background
|
||||
{
|
||||
# nullable enable
|
||||
/// <summary>
|
||||
/// Сервис для фонового выполнения работы
|
||||
/// </summary>
|
||||
public class BackgroundWorkerService : BackgroundService
|
||||
{
|
||||
private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
|
||||
private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2);
|
||||
private static readonly TimeSpan exceptionHandleTimeout = TimeSpan.FromSeconds(2);
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly WorkQueue workQueue = new WorkQueue();
|
||||
|
||||
public BackgroundWorkerService(IServiceProvider serviceProvider)
|
||||
{
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <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 Delete(string id)
|
||||
{
|
||||
return workQueue.Delete(id);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken token)
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
var dateStart = DateTime.Now;
|
||||
var work = workQueue.Pop();
|
||||
if (work is null)
|
||||
{
|
||||
await Task.Delay(executePeriod, token);
|
||||
continue;
|
||||
}
|
||||
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
try
|
||||
{
|
||||
var task = work.ActionAsync(work.Id, scope.ServiceProvider, token);
|
||||
await task.WaitAsync(work.Timeout, token);
|
||||
|
||||
work.ExecutionTime = DateTime.Now - dateStart;
|
||||
Trace.TraceInformation($"Backgroud work:\"{work.Id}\" done. ExecutionTime: {work.ExecutionTime:hh\\:mm\\:ss\\.fff}");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Trace.TraceError($"Backgroud work:\"{work.Id}\" throw exception: {exception.Message}");
|
||||
if (work.OnErrorAsync is not null)
|
||||
{
|
||||
using var task = Task.Run(
|
||||
async () => await work.OnErrorAsync(work.Id, exception, token),
|
||||
token);
|
||||
await task.WaitAsync(exceptionHandleTimeout, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(minDelay, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Background
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// Класс разовой работы.
|
||||
/// Разовая работа приоритетнее периодической.
|
||||
/// </summary>
|
||||
public class WorkBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки.
|
||||
/// </summary>
|
||||
public string Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Делегат работы.
|
||||
/// <para>
|
||||
/// Параметры:
|
||||
/// <list type="number">
|
||||
/// <item>
|
||||
/// <term>string</term>
|
||||
/// <description>Id Идентификатор работы</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>IServiceProvider</term>
|
||||
/// <description>Поставщик сервисов</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>CancellationToken</term>
|
||||
/// <description>Токен отмены задачи</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public Func<string, IServiceProvider, CancellationToken, Task> ActionAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Делегат обработки ошибки.
|
||||
/// Не должен выполняться долго.
|
||||
/// </summary>
|
||||
public Func<string, Exception, CancellationToken, Task>? OnErrorAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// максимально допустимое время выполнения работы
|
||||
/// </summary>
|
||||
public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);
|
||||
|
||||
/// <summary>
|
||||
/// Фактическое время успешного выполнения работы
|
||||
/// </summary>
|
||||
public TimeSpan? ExecutionTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Время последнего запуска
|
||||
/// </summary>
|
||||
public DateTime LastStart { get; set; }
|
||||
|
||||
public WorkBase(string id, Func<string, IServiceProvider, CancellationToken, Task> actionAsync)
|
||||
{
|
||||
Id = id;
|
||||
ActionAsync = actionAsync;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Background
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// Класс периодической работы.
|
||||
/// </summary>
|
||||
public class WorkPeriodic : WorkBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Период выполнения задачи
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Время следующего запуска
|
||||
/// </summary>
|
||||
public DateTime NextStart => LastStart + Period;
|
||||
|
||||
/// <summary>
|
||||
/// Класс периодической работы
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки</param>
|
||||
/// <param name="actionAsync">Делегат работы</param>
|
||||
/// <param name="period">Период выполнения задачи</param>
|
||||
public WorkPeriodic(string id, Func<string, IServiceProvider, CancellationToken, Task> actionAsync, TimeSpan period)
|
||||
:base(id, actionAsync)
|
||||
{
|
||||
Period = period;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Background
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Очередь работ
|
||||
/// </para>
|
||||
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
|
||||
/// </summary>
|
||||
class WorkQueue
|
||||
{
|
||||
private Queue<WorkBase> Primary = new (8);
|
||||
private readonly List<WorkPeriodic> Periodic = new (8);
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
work.LastStart = DateTime.Now;
|
||||
return work;
|
||||
}
|
||||
|
||||
private WorkPeriodic? GetNextPeriodic()
|
||||
{
|
||||
var work = Periodic
|
||||
.OrderBy(w => w.NextStart)
|
||||
.ThenByDescending(w => w.Period)
|
||||
.FirstOrDefault();
|
||||
return work;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Сервис выстраивает очередь из фоновых задач. Ограничивает количество одновременно выполняющихся задач.
|
||||
/// </summary>
|
||||
public class BackgroundWorkerService : IDisposable, IBackgroundWorkerService
|
||||
{
|
||||
private readonly Worker[] workers;
|
||||
private readonly Dictionary<string, Work> works = new Dictionary<string, Work>();
|
||||
private bool isRunning = false;
|
||||
private CancellationTokenSource cts;
|
||||
private Task task;
|
||||
|
||||
public BackgroundWorkerService(IConfiguration configuration)
|
||||
{
|
||||
var workersCount = configuration.GetValue("BackgroundWorkersCount", 4);
|
||||
workers = new Worker[workersCount];
|
||||
for (int i = 0; i < workers.Length; i++)
|
||||
workers[i] = new Worker();
|
||||
}
|
||||
|
||||
~BackgroundWorkerService()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public string Enqueue(Func<string, CancellationToken, Task> func)
|
||||
{
|
||||
var work = new Work
|
||||
{
|
||||
ActionAsync = func
|
||||
};
|
||||
return Enqueue(work);
|
||||
}
|
||||
|
||||
public string Enqueue(string id, Func<string, CancellationToken, Task> func)
|
||||
{
|
||||
var work = new Work(id, func);
|
||||
return Enqueue(work);
|
||||
}
|
||||
|
||||
public string Enqueue(string id, Func<string, CancellationToken, Task> func, Func<string, Exception, CancellationToken, Task> onError)
|
||||
{
|
||||
var work = new Work(id, func)
|
||||
{
|
||||
OnErrorAsync = onError
|
||||
};
|
||||
return Enqueue(work);
|
||||
}
|
||||
|
||||
string Enqueue(Work work)
|
||||
{
|
||||
works[work.Id] = work;
|
||||
if (!isRunning)
|
||||
{
|
||||
isRunning = true;
|
||||
cts = new CancellationTokenSource();
|
||||
task = Task.Run(() => ExecuteAsync(cts.Token), cts.Token);
|
||||
}
|
||||
return work.Id;
|
||||
}
|
||||
|
||||
private Work Dequeue()
|
||||
{
|
||||
var item = works.First();
|
||||
works.Remove(item.Key);
|
||||
return item.Value;
|
||||
}
|
||||
|
||||
public bool TryRemove(string id)
|
||||
=> works.Remove(id);
|
||||
|
||||
public bool Contains(string id)
|
||||
=> works.ContainsKey(id);
|
||||
|
||||
protected async Task ExecuteAsync(CancellationToken token)
|
||||
{
|
||||
while (works.Any() && !token.IsCancellationRequested)
|
||||
{
|
||||
var freeworker = workers.FirstOrDefault(w => !w.IsBusy);
|
||||
if (freeworker is not null)
|
||||
{
|
||||
var work = Dequeue();
|
||||
freeworker.Start(work);
|
||||
}
|
||||
else
|
||||
await Task.Delay(10, token).ConfigureAwait(false);
|
||||
}
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cts?.Cancel();
|
||||
task?.Wait(1);
|
||||
task?.Dispose();
|
||||
cts?.Dispose();
|
||||
task = null;
|
||||
cts = null;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
class Worker : IDisposable
|
||||
{
|
||||
private CancellationTokenSource cts;
|
||||
private Task task;
|
||||
public bool IsBusy { get; private set; }
|
||||
|
||||
~Worker()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void Start(Work work)
|
||||
{
|
||||
IsBusy = true;
|
||||
cts = new CancellationTokenSource();
|
||||
task = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var actionTask = work.ActionAsync(work.Id, cts.Token);
|
||||
await actionTask.WaitAsync(TimeSpan.FromMinutes(2), cts.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError(ex.Message);
|
||||
|
||||
if (work.OnErrorAsync is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await work.OnErrorAsync(work.Id, ex, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception exOnErrorHandler)
|
||||
{
|
||||
Trace.TraceError(exOnErrorHandler.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts?.Dispose();
|
||||
cts = null;
|
||||
IsBusy = false;
|
||||
}
|
||||
}, cts.Token);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
cts?.Cancel();
|
||||
task?.Wait(1);
|
||||
task = null;
|
||||
cts?.Dispose();
|
||||
cts = null;
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
class Work
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public Func<string, CancellationToken, Task> ActionAsync { get; set; }
|
||||
public Func<string, Exception, CancellationToken, Task> OnErrorAsync { get; set; }
|
||||
|
||||
public Work()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
public Work(string id, Func<string, CancellationToken, Task> actionAsync)
|
||||
{
|
||||
Id = id;
|
||||
ActionAsync = actionAsync;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,11 @@ using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -16,6 +17,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
{
|
||||
# nullable enable
|
||||
public class DrillingProgramService : IDrillingProgramService
|
||||
{
|
||||
private static readonly Dictionary<string, DrillingProgramCreateError> drillingProgramCreateErrors = new Dictionary<string, DrillingProgramCreateError>();
|
||||
@ -25,9 +27,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private readonly IUserRepository userRepository;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly IBackgroundWorkerService backgroundWorker;
|
||||
private readonly BackgroundWorker backgroundWorker;
|
||||
private readonly IEmailService emailService;
|
||||
private readonly string connectionString;
|
||||
|
||||
private const int idFileCategoryDrillingProgram = 1000;
|
||||
private const int idFileCategoryDrillingProgramPartsStart = 1001;
|
||||
@ -55,7 +56,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
IUserRepository userRepository,
|
||||
IWellService wellService,
|
||||
IConfiguration configuration,
|
||||
IBackgroundWorkerService backgroundWorker,
|
||||
BackgroundWorker backgroundWorker,
|
||||
IEmailService emailService)
|
||||
{
|
||||
this.context = context;
|
||||
@ -64,7 +65,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
this.wellService = wellService;
|
||||
this.configuration = configuration;
|
||||
this.backgroundWorker = backgroundWorker;
|
||||
this.connectionString = configuration.GetConnectionString("DefaultConnection");
|
||||
this.emailService = emailService;
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
{
|
||||
Parts = parts,
|
||||
Program = files.FirstOrDefault(f => f.IdCategory == idFileCategoryDrillingProgram)
|
||||
.Adapt<FileInfoDto>(),
|
||||
?.Adapt<FileInfoDto>(),
|
||||
PermissionToEdit = userRepository.HasPermission(idUser, "DrillingProgram.edit"),
|
||||
};
|
||||
|
||||
@ -157,7 +157,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
else
|
||||
state.IdState = idStateNotInitialized;
|
||||
|
||||
await TryEnqueueMakeProgramAsync(idWell, state, token);
|
||||
await EnqueueMakeProgramWorkAsync(idWell, state, token);
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -299,7 +299,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p => p.IdWell == fileInfo.IdWell && p.IdFileCategory == fileInfo.IdCategory, token);
|
||||
|
||||
var user = part.RelatedUsers.FirstOrDefault(r => r.IdUser == idUser && r.IdUserRole == idUserRoleApprover)?.User;
|
||||
var user = part?.RelatedUsers.FirstOrDefault(r => r.IdUser == idUser && r.IdUserRole == idUserRoleApprover)?.User;
|
||||
if (user is null)
|
||||
throw new ForbidException($"User {idUser} is not in the approvers list.");
|
||||
|
||||
@ -323,11 +323,11 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
else
|
||||
{
|
||||
// если все согласованты согласовали - оповещаем публикатора
|
||||
var approvers = part.RelatedUsers
|
||||
var approvers = part!.RelatedUsers
|
||||
.Where(u => u.IdUserRole == idUserRoleApprover);
|
||||
if (approvers
|
||||
.All(user => fileInfo.FileMarks
|
||||
.Any(mark => (mark.IdMarkType == idMarkTypeApprove && mark.User.Id == user.IdUser && !mark.IsDeleted)) ||
|
||||
?.Any(mark => (mark.IdMarkType == idMarkTypeApprove && mark.User.Id == user.IdUser && !mark.IsDeleted)) == true ||
|
||||
(fileMarkDto.IdMarkType == idMarkTypeApprove && user.IdUser == idUser)))
|
||||
{
|
||||
await NotifyPublisherOnFullAccepAsync(fileMarkDto, token);
|
||||
@ -359,7 +359,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token)
|
||||
{
|
||||
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file.IdWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file!.IdWell, token);
|
||||
var user = file.Author;
|
||||
var factory = new DrillingMailBodyFactory(configuration);
|
||||
var subject = factory.MakeSubject(well, "Загруженный вами документ полностью согласован");
|
||||
@ -371,7 +371,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
||||
{
|
||||
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file.IdWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file!.IdWell, token);
|
||||
var user = file.Author;
|
||||
var factory = new DrillingMailBodyFactory(configuration);
|
||||
var subject = factory.MakeSubject(well, "Загруженный вами документ отклонен");
|
||||
@ -405,12 +405,12 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
emailService.EnqueueSend(user.Email, subject, body);
|
||||
}
|
||||
|
||||
private DrillingProgramPartDto ConvertPart(int idUser, List<FileCategory> fileCategories, List<AsbCloudDb.Model.FileInfo> files, DrillingProgramPart partEntity, double timezoneOffset)
|
||||
private static DrillingProgramPartDto ConvertPart(int idUser, List<FileCategory> fileCategories, List<AsbCloudDb.Model.FileInfo> files, DrillingProgramPart partEntity, double timezoneOffset)
|
||||
{
|
||||
var part = new DrillingProgramPartDto
|
||||
{
|
||||
IdFileCategory = partEntity.IdFileCategory,
|
||||
Name = fileCategories.FirstOrDefault(c => c.Id == partEntity.IdFileCategory).Name,
|
||||
Name = fileCategories.FirstOrDefault(c => c.Id == partEntity.IdFileCategory)!.Name,
|
||||
Approvers = partEntity.RelatedUsers
|
||||
.Where(r => r.IdUserRole == idUserRoleApprover)
|
||||
.Select(r => r.User.Adapt<UserDto>()),
|
||||
@ -464,31 +464,27 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
return part;
|
||||
}
|
||||
|
||||
private async Task TryEnqueueMakeProgramAsync(int idWell, DrillingProgramStateDto state, CancellationToken token)
|
||||
private async Task EnqueueMakeProgramWorkAsync(int idWell, DrillingProgramStateDto state, CancellationToken token)
|
||||
{
|
||||
if (state.IdState == idStateCreating)
|
||||
{
|
||||
var workId = MakeWorkId(idWell);
|
||||
if (!backgroundWorker.Contains(workId))
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
var well = (await wellService.GetOrDefaultAsync(idWell, token))!;
|
||||
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.xlsx";
|
||||
var tempResultFilePath = Path.Combine(Path.GetTempPath(), "drillingProgram", resultFileName);
|
||||
async Task funcProgramMake(string id, CancellationToken token)
|
||||
|
||||
var workAction = async (string workId, IServiceProvider serviceProvider, CancellationToken token) =>
|
||||
{
|
||||
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||
.UseNpgsql(connectionString)
|
||||
.Options;
|
||||
using var context = new AsbCloudDbContext(contextOptions);
|
||||
var fileRepository = new FileRepository(context);
|
||||
var fileStorageRepository = new FileStorageRepository();
|
||||
var fileService = new FileService(fileRepository, fileStorageRepository);
|
||||
var context = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||
var fileService = serviceProvider.GetRequiredService<FileService>();
|
||||
var files = state.Parts.Select(p => fileService.GetUrl(p.File));
|
||||
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well);
|
||||
await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token);
|
||||
}
|
||||
};
|
||||
|
||||
Task funcOnErrorProgramMake(string workId, Exception exception, CancellationToken token)
|
||||
var onErrorAction = (string workId, Exception exception, CancellationToken token) =>
|
||||
{
|
||||
var message = $"Не удалось сформировать программу бурения по скважине {well?.Caption}";
|
||||
drillingProgramCreateErrors[workId] = new()
|
||||
@ -497,9 +493,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
Exception = exception.Message,
|
||||
};
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
|
||||
backgroundWorker.Enqueue(workId, funcProgramMake, funcOnErrorProgramMake);
|
||||
var work = new WorkBase(workId, workAction)
|
||||
{
|
||||
ExecutionTime = TimeSpan.FromMinutes(1),
|
||||
OnErrorAsync = onErrorAction
|
||||
};
|
||||
|
||||
backgroundWorker.Push(work);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -513,7 +515,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task<int> RemoveDrillingProgramAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var workId = MakeWorkId(idWell);
|
||||
backgroundWorker.TryRemove(workId);
|
||||
backgroundWorker.Delete(workId);
|
||||
|
||||
var filesIds = await context.Files
|
||||
.Where(f => f.IdWell == idWell &&
|
||||
@ -529,4 +531,5 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private static string MakeWorkId(int idWell)
|
||||
=> $"Make drilling program for wellId {idWell}";
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -8,26 +8,28 @@ using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
#nullable enable
|
||||
public class EmailService : IEmailService
|
||||
{
|
||||
private readonly IBackgroundWorkerService backgroundWorker;
|
||||
private readonly BackgroundWorker backgroundWorker;
|
||||
private readonly bool IsConfigured;
|
||||
private readonly string sender;
|
||||
private readonly string smtpServer;
|
||||
private readonly string smtpPassword;
|
||||
|
||||
public EmailService(IBackgroundWorkerService backgroundWorker, IConfiguration configuration)
|
||||
public EmailService(BackgroundWorker backgroundWorker, IConfiguration configuration)
|
||||
{
|
||||
sender = configuration.GetValue<string>("email:sender", null);
|
||||
smtpPassword = configuration.GetValue<string>("email:password", null);
|
||||
smtpServer = configuration.GetValue<string>("email:smtpServer", null);
|
||||
sender = configuration.GetValue("email:sender", string.Empty);
|
||||
smtpPassword = configuration.GetValue("email:password", string.Empty);
|
||||
smtpServer = configuration.GetValue("email:smtpServer", string.Empty);
|
||||
|
||||
var configError = (string.IsNullOrEmpty(sender) ||
|
||||
var configError = string.IsNullOrEmpty(sender) ||
|
||||
string.IsNullOrEmpty(smtpPassword) ||
|
||||
string.IsNullOrEmpty(smtpServer));
|
||||
string.IsNullOrEmpty(smtpServer);
|
||||
|
||||
IsConfigured = !configError;
|
||||
|
||||
@ -44,20 +46,21 @@ namespace AsbCloudInfrastructure.Services
|
||||
Trace.TraceWarning("smtp is not configured");
|
||||
return;
|
||||
}
|
||||
var jobId = CalcJobId(addresses, subject, htmlBody);
|
||||
if (!backgroundWorker.Contains(jobId))
|
||||
var workId = MakeWorkId(addresses, subject, htmlBody);
|
||||
if (!backgroundWorker.Contains(workId))
|
||||
{
|
||||
var action = MakeEmailSendJobAsync(addresses, subject, htmlBody);
|
||||
backgroundWorker.Enqueue(jobId, action);
|
||||
var workAction = MakeEmailSendWorkAction(addresses, subject, htmlBody);
|
||||
var work = new WorkBase(workId, workAction);
|
||||
backgroundWorker.Push(work);
|
||||
}
|
||||
}
|
||||
|
||||
private Func<string, CancellationToken, Task> MakeEmailSendJobAsync(IEnumerable<string> addresses, string subject, string htmlBody)
|
||||
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(IEnumerable<string> addresses, string subject, string htmlBody)
|
||||
{
|
||||
var mailAddresses = new List<MailAddress>();
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
if (MailAddress.TryCreate(address, out MailAddress mailAddress))
|
||||
if (MailAddress.TryCreate(address, out MailAddress? mailAddress))
|
||||
mailAddresses.Add(mailAddress);
|
||||
else
|
||||
Trace.TraceWarning($"Mail {address} is not correct.");
|
||||
@ -69,16 +72,16 @@ namespace AsbCloudInfrastructure.Services
|
||||
if (string.IsNullOrEmpty(subject))
|
||||
throw new ArgumentInvalidException($"{nameof(subject)} should be set", nameof(subject));
|
||||
|
||||
var func = async (string id, CancellationToken token) =>
|
||||
var workAction = async (string id, IServiceProvider serviceProvider, CancellationToken token) =>
|
||||
{
|
||||
var from = new MailAddress(sender);
|
||||
|
||||
var message = new MailMessage();
|
||||
message.From = from;
|
||||
var message = new MailMessage
|
||||
{
|
||||
From = from
|
||||
};
|
||||
|
||||
foreach (var mailAddress in mailAddresses)
|
||||
message.To.Add(mailAddress);
|
||||
//message.To.Add("support@digitaldrilling.ru");
|
||||
|
||||
message.BodyEncoding = System.Text.Encoding.UTF8;
|
||||
message.Body = htmlBody;
|
||||
@ -91,12 +94,12 @@ namespace AsbCloudInfrastructure.Services
|
||||
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
||||
|
||||
await client.SendMailAsync(message, token);
|
||||
Trace.TraceInformation($"Send email to {string.Join(',', addresses)} subj:{subject} html body count {htmlBody.Count()}");
|
||||
Trace.TraceInformation($"Send email to {string.Join(',', addresses)} subj:{subject} html body count {htmlBody.Length}");
|
||||
};
|
||||
return func;
|
||||
return workAction;
|
||||
}
|
||||
|
||||
private string CalcJobId(IEnumerable<string> addresses, string subject, string content)
|
||||
private static string MakeWorkId(IEnumerable<string> addresses, string subject, string content)
|
||||
{
|
||||
var hash = GetHashCode(addresses);
|
||||
hash ^= subject.GetHashCode();
|
||||
@ -114,4 +117,5 @@ namespace AsbCloudInfrastructure.Services
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using AsbSaubReport;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -15,30 +15,32 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
#nullable enable
|
||||
public class ReportService : IReportService
|
||||
{
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly string connectionString;
|
||||
private readonly ITelemetryService telemetryService;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IBackgroundWorkerService backgroundWorkerService;
|
||||
|
||||
public ReportService(IAsbCloudDbContext db, IConfiguration configuration,
|
||||
ITelemetryService telemetryService, IWellService wellService, IBackgroundWorkerService backgroundWorkerService)
|
||||
{
|
||||
this.db = db;
|
||||
this.connectionString = configuration.GetConnectionString("DefaultConnection");
|
||||
this.wellService = wellService;
|
||||
this.backgroundWorkerService = backgroundWorkerService;
|
||||
this.telemetryService = telemetryService;
|
||||
ReportCategoryId = db.FileCategories.AsNoTracking()
|
||||
.FirstOrDefault(c =>
|
||||
c.Name.Equals("Рапорт")).Id;
|
||||
}
|
||||
private readonly BackgroundWorker backgroundWorkerService;
|
||||
|
||||
public int ReportCategoryId { get; private set; }
|
||||
|
||||
public string CreateReport(int idWell, int idUser, int stepSeconds, int format, DateTime begin,
|
||||
public ReportService(IAsbCloudDbContext db,
|
||||
ITelemetryService telemetryService,
|
||||
IWellService wellService,
|
||||
BackgroundWorker backgroundWorkerService)
|
||||
{
|
||||
this.db = db;
|
||||
this.wellService = wellService;
|
||||
this.backgroundWorkerService = backgroundWorkerService;
|
||||
this.telemetryService = telemetryService;
|
||||
ReportCategoryId = db.FileCategories
|
||||
.AsNoTracking()
|
||||
.First(c => c.Name.Equals("Рапорт"))
|
||||
.Id;
|
||||
}
|
||||
|
||||
public string EnqueueCreateReportWork(int idWell, int idUser, int stepSeconds, int format, DateTime begin,
|
||||
DateTime end, Action<object, string> progressHandler)
|
||||
{
|
||||
var timezoneOffset = wellService.GetTimezone(idWell).Hours;
|
||||
@ -47,12 +49,12 @@ namespace AsbCloudInfrastructure.Services
|
||||
var beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset);
|
||||
var endRemote = end.ToTimeZoneOffsetHours(timezoneOffset);
|
||||
|
||||
var newReportId = backgroundWorkerService.Enqueue(async (id, token) =>
|
||||
var workId = $"create report by wellid:{idWell} for userid:{idUser} requested at {DateTime.Now}";
|
||||
|
||||
var workAction = async (string id, IServiceProvider serviceProvider, CancellationToken token) =>
|
||||
{
|
||||
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||
.UseNpgsql(connectionString)
|
||||
.Options;
|
||||
using var context = new AsbCloudDbContext(contextOptions);
|
||||
using var context = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||
var fileService = serviceProvider.GetRequiredService<FileService>();
|
||||
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), "report");
|
||||
|
||||
@ -65,11 +67,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
progressHandler.Invoke(e.Adapt<ReportProgressDto>(), id);
|
||||
};
|
||||
generator.Make(reportFileName);
|
||||
|
||||
var fileRepository = new FileRepository(context);
|
||||
var fileStorageRepository = new FileStorageRepository();
|
||||
var fileService = new FileService(fileRepository, fileStorageRepository);
|
||||
var fileInfo = await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token);
|
||||
|
||||
var fileInfo = (await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token))!;
|
||||
|
||||
progressHandler.Invoke(new
|
||||
{
|
||||
@ -91,13 +90,17 @@ namespace AsbCloudInfrastructure.Services
|
||||
};
|
||||
context.ReportProperties.Add(newReportProperties);
|
||||
context.SaveChanges();
|
||||
});
|
||||
};
|
||||
|
||||
var work = new WorkBase(workId, workAction);
|
||||
backgroundWorkerService.Push(work);
|
||||
|
||||
progressHandler.Invoke(new ReportProgressDto
|
||||
{
|
||||
Operation = "Ожидает начала в очереди.",
|
||||
Progress = 0f,
|
||||
}, newReportId);
|
||||
return newReportId;
|
||||
}, workId);
|
||||
return workId;
|
||||
}
|
||||
|
||||
public int GetReportPagesCount(int idWell, DateTime begin, DateTime end, int stepSeconds, int format)
|
||||
@ -106,12 +109,12 @@ namespace AsbCloudInfrastructure.Services
|
||||
var beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset);
|
||||
var endRemote = end.ToTimeZoneOffsetHours(timezoneOffset);
|
||||
|
||||
var generator = GetReportGenerator(idWell, beginRemote, endRemote, stepSeconds, format, (AsbCloudDbContext)db);
|
||||
var generator = GetReportGenerator(idWell, beginRemote, endRemote, stepSeconds, format, db);
|
||||
var pagesCount = generator.GetPagesCount();
|
||||
return pagesCount;
|
||||
}
|
||||
|
||||
public DatesRangeDto GetDatesRangeOrDefault(int idWell)
|
||||
public DatesRangeDto? GetDatesRangeOrDefault(int idWell)
|
||||
{
|
||||
var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
|
||||
if (idTelemetry is null)
|
||||
@ -128,8 +131,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
.OrderBy(o => o.File.UploadDate)
|
||||
.AsNoTracking()
|
||||
.Take(1024);
|
||||
var properties = await propertiesQuery.ToListAsync(token);
|
||||
return properties.Select(p => new ReportPropertiesDto
|
||||
var entities = await propertiesQuery.ToListAsync(token);
|
||||
var dtos = entities.Select(p => new ReportPropertiesDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Name = p.File.Name,
|
||||
@ -151,10 +154,11 @@ namespace AsbCloudInfrastructure.Services
|
||||
Step = p.Step,
|
||||
Format = p.Format == 0 ? ".pdf" : ".las"
|
||||
});
|
||||
return dtos;
|
||||
}
|
||||
|
||||
private static IReportGenerator GetReportGenerator(int idWell, DateTime begin,
|
||||
DateTime end, int stepSeconds, int format, AsbCloudDbContext context)
|
||||
DateTime end, int stepSeconds, int format, IAsbCloudDbContext context)
|
||||
{
|
||||
var dataSource = new ReportDataSourcePgCloud(context, idWell);
|
||||
IReportGenerator generator = format switch
|
||||
@ -173,4 +177,5 @@ namespace AsbCloudInfrastructure.Services
|
||||
return generator;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using AsbCloudInfrastructure.Services.DrillingProgram;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@ -83,8 +83,8 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
private readonly Mock<IUserRepository> userRepositoryMock;
|
||||
private readonly Mock<IWellService> wellServiceMock;
|
||||
private readonly Mock<IConfiguration> configurationMock;
|
||||
private readonly Mock<IBackgroundWorkerService> backgroundWorkerMock;
|
||||
private readonly Mock<IEmailService> emailService;
|
||||
private readonly Mock<BackgroundWorker> backgroundWorkerMock;
|
||||
private readonly Mock<IEmailService> emailServiceMock;
|
||||
|
||||
public DrillingProgramServiceTest()
|
||||
{
|
||||
@ -102,7 +102,8 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
userRepositoryMock = new Mock<IUserRepository>();
|
||||
wellServiceMock = new Mock<IWellService>();
|
||||
configurationMock = new Mock<IConfiguration>();
|
||||
backgroundWorkerMock = new Mock<IBackgroundWorkerService>();
|
||||
backgroundWorkerMock = new Mock<BackgroundWorker>();
|
||||
emailServiceMock = new Mock<IEmailService>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -115,7 +116,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var users = await service.GetAvailableUsers(idWell, CancellationToken.None);
|
||||
|
||||
@ -132,7 +133,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var result = await service.AddPartsAsync(idWell, new int[] { 1001, 1002 }, CancellationToken.None);
|
||||
|
||||
@ -151,7 +152,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var result = await service.RemovePartsAsync(idWell, new int[] { 1005 }, CancellationToken.None);
|
||||
|
||||
@ -174,7 +175,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var result = await service.AddUserAsync(idWell, 1001, publisher1.Id, 1, CancellationToken.None);
|
||||
|
||||
@ -209,7 +210,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var result = await service.RemoveUserAsync(idWell, idFileCategory, publisher1.Id, idUserRole, CancellationToken.None);
|
||||
|
||||
@ -235,7 +236,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var fileMark = new FileMarkDto
|
||||
{
|
||||
@ -266,7 +267,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
var fileMark = new FileMarkDto
|
||||
{
|
||||
IdFile = file1001.Id,
|
||||
@ -304,7 +305,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var fileMark = new FileMarkDto
|
||||
{
|
||||
@ -331,7 +332,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||
|
||||
@ -358,12 +359,12 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||
|
||||
Assert.Equal(2, state.IdState);
|
||||
backgroundWorkerMock.Verify(s => s.Enqueue(It.IsAny<Func<string, CancellationToken, Task>>()));
|
||||
backgroundWorkerMock.Verify(s => s.Push(It.IsAny<WorkBase>()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -388,7 +389,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
wellServiceMock.Object,
|
||||
configurationMock.Object,
|
||||
backgroundWorkerMock.Object,
|
||||
emailService.Object);
|
||||
emailServiceMock.Object);
|
||||
|
||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||
|
||||
|
@ -68,7 +68,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
).ConfigureAwait(false);
|
||||
}, token);
|
||||
|
||||
var id = reportService.CreateReport(idWell, (int)idUser,
|
||||
var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser,
|
||||
stepSeconds, format, begin, end, HandleReportProgressAsync);
|
||||
|
||||
return Ok(id);
|
||||
|
Loading…
Reference in New Issue
Block a user