forked from ddrilling/AsbCloudServer
Merge branch 'dev' into WellOperationTree/refact_migration
This commit is contained in:
commit
81d3ef3146
@ -29,7 +29,7 @@ namespace AsbCloudApp.Data
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Включенные роли
|
/// Включенные роли
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ICollection<UserRoleDto> Roles { get; set; }
|
public virtual IEnumerable<UserRoleDto> Roles { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Пользователи в роли
|
/// Пользователи в роли
|
||||||
|
@ -11,7 +11,7 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сервис доступа к файлам
|
/// Сервис доступа к файлам
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFileRepository : ICrudService<FileInfoDto>
|
public interface IFileRepository : ICrudRepository<FileInfoDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение файлов по скважине
|
/// Получение файлов по скважине
|
||||||
|
@ -7,7 +7,7 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Репозиторий пользователей
|
/// Репозиторий пользователей
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IUserRepository : ICrudService<UserExtendedDto>
|
public interface IUserRepository : ICrudRepository<UserExtendedDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить список всех прав пользователя (включая наследование групп)
|
/// Получить список всех прав пользователя (включая наследование групп)
|
||||||
|
@ -10,7 +10,7 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Разрешения на доступ к данным
|
/// Разрешения на доступ к данным
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IUserRoleRepository : ICrudService<UserRoleDto>
|
public interface IUserRoleRepository : ICrudRepository<UserRoleDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// получить dto по названиям
|
/// получить dto по названиям
|
||||||
|
@ -73,7 +73,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="fileStream"></param>
|
/// <param name="fileStream"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <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)
|
string fileFullName, Stream fileStream, CancellationToken token)
|
||||||
{
|
{
|
||||||
//save info to db
|
//save info to db
|
||||||
@ -93,7 +93,7 @@ namespace AsbCloudApp.Services
|
|||||||
string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId);
|
string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId);
|
||||||
await fileStorageRepository.SaveFileAsync(filePath, fileStream, token);
|
await fileStorageRepository.SaveFileAsync(filePath, fileStream, token);
|
||||||
|
|
||||||
return await GetOrDefaultAsync(fileId, token);
|
return (await GetOrDefaultAsync(fileId, token))!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// Сервис получения, добавления, изменения, удаления данных
|
/// Сервис получения, добавления, изменения, удаления данных
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TDto"></typeparam>
|
/// <typeparam name="TDto"></typeparam>
|
||||||
public interface ICrudService<TDto>
|
public interface ICrudRepository<TDto>
|
||||||
where TDto : Data.IId
|
where TDto : Data.IId
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
@ -8,7 +8,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The параметры бурения service.
|
/// The параметры бурения service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDrillParamsService : ICrudService<DrillParamsDto>
|
public interface IDrillParamsService : ICrudRepository<DrillParamsDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// default параметры бурения
|
/// default параметры бурения
|
||||||
|
@ -19,6 +19,12 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<LimitingParameterDto>> GetStatAsync(LimitingParameterRequest request, CancellationToken token);
|
Task<IEnumerable<LimitingParameterDto>> GetStatAsync(LimitingParameterRequest request, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение списка ограничений
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Dictionary<int, string> GetLimitingParameteraNames();
|
||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudApp.Services
|
namespace AsbCloudApp.Services
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сервис рапортов
|
/// Сервис рапортов
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -16,7 +17,6 @@ namespace AsbCloudApp.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int ReportCategoryId { get; }
|
int ReportCategoryId { get; }
|
||||||
|
|
||||||
// TODO: rename this method
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Поставить рапорт в очередь на формирование
|
/// Поставить рапорт в очередь на формирование
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -28,7 +28,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="end"></param>
|
/// <param name="end"></param>
|
||||||
/// <param name="handleReportProgress"></param>
|
/// <param name="handleReportProgress"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string CreateReport(int idWell, int idUser, int stepSeconds,
|
string EnqueueCreateReportWork(int idWell, int idUser, int stepSeconds,
|
||||||
int format, DateTime begin, DateTime end,
|
int format, DateTime begin, DateTime end,
|
||||||
Action<object, string> handleReportProgress);
|
Action<object, string> handleReportProgress);
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
DatesRangeDto GetDatesRangeOrDefault(int idWell);
|
DatesRangeDto? GetDatesRangeOrDefault(int idWell);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Список готовых рапортов
|
/// Список готовых рапортов
|
||||||
@ -58,5 +58,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token);
|
Task<IEnumerable<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token);
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// Для сущностей относящихся к скважине
|
/// Для сущностей относящихся к скважине
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="Tdto"></typeparam>
|
/// <typeparam name="Tdto"></typeparam>
|
||||||
public interface IRepositoryWellRelated<Tdto> : ICrudService<Tdto>
|
public interface IRepositoryWellRelated<Tdto> : ICrudRepository<Tdto>
|
||||||
where Tdto : IId, IWellRelated
|
where Tdto : IId, IWellRelated
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -9,7 +9,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// сервис скважин
|
/// сервис скважин
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWellService : ICrudService<WellDto>
|
public interface IWellService : ICrudRepository<WellDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// сервис телеметрии
|
/// сервис телеметрии
|
||||||
|
@ -61,19 +61,31 @@ namespace AsbCloudDb.Model
|
|||||||
public DbSet<WITS.Record60> Record60 => Set<WITS.Record60>();
|
public DbSet<WITS.Record60> Record60 => Set<WITS.Record60>();
|
||||||
public DbSet<WITS.Record61> Record61 => Set<WITS.Record61>();
|
public DbSet<WITS.Record61> Record61 => Set<WITS.Record61>();
|
||||||
|
|
||||||
|
public static int ReferenceCount { get; private set; }
|
||||||
|
|
||||||
public AsbCloudDbContext() : base()
|
public AsbCloudDbContext() : base()
|
||||||
{
|
{
|
||||||
|
ReferenceCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsbCloudDbContext(DbContextOptions<AsbCloudDbContext> options)
|
public AsbCloudDbContext(DbContextOptions<AsbCloudDbContext> options)
|
||||||
: base(options)
|
: base(options)
|
||||||
{
|
{
|
||||||
|
ReferenceCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsbCloudDbContext()
|
||||||
|
{
|
||||||
|
ReferenceCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!optionsBuilder.IsConfigured)
|
if (!optionsBuilder.IsConfigured)
|
||||||
optionsBuilder.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True");
|
optionsBuilder.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True"
|
||||||
|
//, builder=>builder.EnableRetryOnFailure(2, System.TimeSpan.FromMinutes(1))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
98
AsbCloudInfrastructure/Background/BackgroundWorker.cs
Normal file
98
AsbCloudInfrastructure/Background/BackgroundWorker.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Background
|
||||||
|
{
|
||||||
|
# nullable enable
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для фонового выполнения работы
|
||||||
|
/// </summary>
|
||||||
|
public class BackgroundWorker : 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 string? CurrentWorkId;
|
||||||
|
public BackgroundWorker(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 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 dateStart = DateTime.Now;
|
||||||
|
var work = workQueue.Pop();
|
||||||
|
if (work is null)
|
||||||
|
{
|
||||||
|
await Task.Delay(executePeriod, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CurrentWorkId = work.Id;
|
||||||
|
using var scope = serviceProvider.CreateScope();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Trace.TraceInformation($"Backgroud work:\"{work.Id}\" start.");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CurrentWorkId = null;
|
||||||
|
await Task.Delay(minDelay, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
69
AsbCloudInfrastructure/Background/WorkBase.cs
Normal file
69
AsbCloudInfrastructure/Background/WorkBase.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.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>
|
||||||
|
internal 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; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Время последнего запуска
|
||||||
|
/// </summary>
|
||||||
|
public DateTime LastStart { get; set; }
|
||||||
|
|
||||||
|
public WorkBase(string id, Func<string, IServiceProvider, CancellationToken, Task> actionAsync)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
ActionAsync = actionAsync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
36
AsbCloudInfrastructure/Background/WorkPeriodic.cs
Normal file
36
AsbCloudInfrastructure/Background/WorkPeriodic.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.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
|
||||||
|
}
|
107
AsbCloudInfrastructure/Background/WorkQueue.cs
Normal file
107
AsbCloudInfrastructure/Background/WorkQueue.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string id)
|
||||||
|
{
|
||||||
|
var result = 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;
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
@ -6,6 +6,7 @@ using AsbCloudApp.Services;
|
|||||||
using AsbCloudApp.Services.Subsystems;
|
using AsbCloudApp.Services.Subsystems;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudDb.Model.Subsystems;
|
using AsbCloudDb.Model.Subsystems;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using AsbCloudInfrastructure.Services.DailyReport;
|
using AsbCloudInfrastructure.Services.DailyReport;
|
||||||
@ -97,16 +98,13 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetService<AsbCloudDbContext>());
|
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetService<AsbCloudDbContext>());
|
||||||
services.AddScoped<IEmailService, EmailService>();
|
services.AddScoped<IEmailService, EmailService>();
|
||||||
|
|
||||||
services.AddHostedService<OperationDetectionBackgroundService>();
|
|
||||||
services.AddHostedService<SubsystemOperationTimeBackgroundService>();
|
|
||||||
services.AddHostedService<LimitingParameterBackgroundService>();
|
|
||||||
services.AddSingleton(new WitsInfoService());
|
services.AddSingleton(new WitsInfoService());
|
||||||
services.AddSingleton(new InstantDataRepository());
|
services.AddSingleton(new InstantDataRepository());
|
||||||
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(configuration));
|
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(configuration));
|
||||||
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
|
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
|
||||||
services.AddSingleton<ITelemetryTracker, TelemetryTracker>();
|
services.AddSingleton<ITelemetryTracker, TelemetryTracker>();
|
||||||
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
||||||
services.AddSingleton<IBackgroundWorkerService, BackgroundWorkerService>();
|
services.AddSingleton<BackgroundWorker>();
|
||||||
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
||||||
|
|
||||||
services.AddTransient<IAuthService, AuthService>();
|
services.AddTransient<IAuthService, AuthService>();
|
||||||
@ -139,33 +137,33 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
||||||
|
|
||||||
// admin crud services:
|
// admin crud services:
|
||||||
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>(s =>
|
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
||||||
new CrudCacheServiceBase<TelemetryDto, Telemetry>(
|
new CrudCacheRepositoryBase<TelemetryDto, Telemetry>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
s.GetService<IMemoryCache>(),
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService
|
dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService
|
||||||
services.AddTransient<ICrudService<DrillParamsDto>, DrillParamsService>();
|
services.AddTransient<ICrudRepository<DrillParamsDto>, DrillParamsService>();
|
||||||
services.AddTransient<ICrudService<DepositDto>, CrudCacheServiceBase<DepositDto, Deposit>>(s =>
|
services.AddTransient<ICrudRepository<DepositDto>, CrudCacheRepositoryBase<DepositDto, Deposit>>(s =>
|
||||||
new CrudCacheServiceBase<DepositDto, Deposit>(
|
new CrudCacheRepositoryBase<DepositDto, Deposit>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
s.GetService<IMemoryCache>(),
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(d => d.Clusters)));
|
dbSet => dbSet.Include(d => d.Clusters)));
|
||||||
services.AddTransient<ICrudService<CompanyDto>, CrudCacheServiceBase<CompanyDto, Company>>(s =>
|
services.AddTransient<ICrudRepository<CompanyDto>, CrudCacheRepositoryBase<CompanyDto, Company>>(s =>
|
||||||
new CrudCacheServiceBase<CompanyDto, Company>(
|
new CrudCacheRepositoryBase<CompanyDto, Company>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
s.GetService<IMemoryCache>(),
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(c => c.CompanyType)));
|
dbSet => dbSet.Include(c => c.CompanyType)));
|
||||||
|
|
||||||
services.AddTransient<ICrudService<CompanyTypeDto>, CrudCacheServiceBase<CompanyTypeDto, CompanyType>>();
|
services.AddTransient<ICrudRepository<CompanyTypeDto>, CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>>();
|
||||||
services.AddTransient<ICrudService<ClusterDto>, CrudCacheServiceBase<ClusterDto, Cluster>>(s =>
|
services.AddTransient<ICrudRepository<ClusterDto>, CrudCacheRepositoryBase<ClusterDto, Cluster>>(s =>
|
||||||
new CrudCacheServiceBase<ClusterDto, Cluster>(
|
new CrudCacheRepositoryBase<ClusterDto, Cluster>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
s.GetService<IMemoryCache>(),
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet
|
dbSet => dbSet
|
||||||
.Include(c => c.Wells)
|
.Include(c => c.Wells)
|
||||||
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
|
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
|
||||||
|
|
||||||
services.AddTransient<ICrudService<DrillerDto>, CrudCacheServiceBase<DrillerDto, Driller>>();
|
services.AddTransient<ICrudRepository<DrillerDto>, CrudCacheRepositoryBase<DrillerDto, Driller>>();
|
||||||
|
|
||||||
services.AddTransient<IFileRepository, FileRepository>();
|
services.AddTransient<IFileRepository, FileRepository>();
|
||||||
services.AddTransient<IFileStorageRepository, FileStorageRepository>();
|
services.AddTransient<IFileStorageRepository, FileStorageRepository>();
|
||||||
@ -174,10 +172,10 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<IUserRepository, UserRepository>();
|
services.AddTransient<IUserRepository, UserRepository>();
|
||||||
services.AddTransient<ILimitingParameterRepository, LimitingParameterRepository>();
|
services.AddTransient<ILimitingParameterRepository, LimitingParameterRepository>();
|
||||||
// Subsystem service
|
// Subsystem service
|
||||||
services.AddTransient<ICrudService<SubsystemDto>, CrudCacheServiceBase<SubsystemDto, Subsystem>>();
|
services.AddTransient<ICrudRepository<SubsystemDto>, CrudCacheRepositoryBase<SubsystemDto, Subsystem>>();
|
||||||
services.AddTransient<ISubsystemService, SubsystemService>();
|
services.AddTransient<ISubsystemService, SubsystemService>();
|
||||||
|
|
||||||
services.AddTransient<ICrudService<PermissionDto>, CrudCacheServiceBase<PermissionDto, Permission>>();
|
services.AddTransient<ICrudRepository<PermissionDto>, CrudCacheRepositoryBase<PermissionDto, Permission>>();
|
||||||
|
|
||||||
// TelemetryData services
|
// TelemetryData services
|
||||||
services.AddTransient<ITelemetryDataService<TelemetryDataSaubDto>, TelemetryDataSaubService>();
|
services.AddTransient<ITelemetryDataService<TelemetryDataSaubDto>, TelemetryDataSaubService>();
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
|
||||||
{
|
|
||||||
public static class Helper
|
|
||||||
{
|
|
||||||
public static T Max<T>(params T[] items)
|
|
||||||
where T : IComparable
|
|
||||||
{
|
|
||||||
var count = items.Length;
|
|
||||||
if (count < 1)
|
|
||||||
throw new ArgumentException("Count of params must be greater than 1");
|
|
||||||
|
|
||||||
var max = items[0];
|
|
||||||
for (var i = 1; i < count; i++)
|
|
||||||
if (max.CompareTo(items[i]) < 0)
|
|
||||||
max = items[i];
|
|
||||||
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T Min<T>(params T[] items)
|
|
||||||
where T : IComparable
|
|
||||||
{
|
|
||||||
var count = items.Length;
|
|
||||||
if (count < 1)
|
|
||||||
throw new ArgumentException("Count of params must be greater than 1");
|
|
||||||
|
|
||||||
var min = items[0];
|
|
||||||
for (var i = 1; i < count; i++)
|
|
||||||
if (min.CompareTo(items[i]) > 0)
|
|
||||||
min = items[i];
|
|
||||||
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (T min, T max) MinMax<T>(params T[] items)
|
|
||||||
where T : IComparable
|
|
||||||
{
|
|
||||||
var count = items.Length;
|
|
||||||
if (count < 1)
|
|
||||||
throw new ArgumentException("Count of params must be greater than 1");
|
|
||||||
|
|
||||||
var min = items[0];
|
|
||||||
var max = items[0];
|
|
||||||
for (var i = 1; i < count; i++)
|
|
||||||
if (max.CompareTo(items[i]) < 0)
|
|
||||||
max = items[i];
|
|
||||||
else if (min.CompareTo(items[i]) > 0)
|
|
||||||
min = items[i];
|
|
||||||
|
|
||||||
return (min, max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
namespace Mapster
|
|
||||||
{
|
|
||||||
public static class MapsterExtension
|
|
||||||
{
|
|
||||||
//public static IEnumerable<TDestination> Adapt<TDestination>(this IEnumerable<object> sourceList)
|
|
||||||
//{
|
|
||||||
// return sourceList.Select(item => item.Adapt<TDestination>());
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@ namespace AsbCloudInfrastructure
|
|||||||
{
|
{
|
||||||
public class ReportDataSourcePgCloud : IReportDataSource
|
public class ReportDataSourcePgCloud : IReportDataSource
|
||||||
{
|
{
|
||||||
private readonly AsbCloudDbContext context;
|
private readonly IAsbCloudDbContext context;
|
||||||
|
|
||||||
private readonly int? idTelemetry;
|
private readonly int? idTelemetry;
|
||||||
private readonly WellInfoReport info;
|
private readonly WellInfoReport info;
|
||||||
@ -25,7 +25,7 @@ namespace AsbCloudInfrastructure
|
|||||||
{3, "Информация"},
|
{3, "Информация"},
|
||||||
};
|
};
|
||||||
|
|
||||||
public ReportDataSourcePgCloud(AsbCloudDbContext context, int idWell)
|
public ReportDataSourcePgCloud(IAsbCloudDbContext context, int idWell)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
public AnalyzeResult Analyze()
|
public AnalyzeResult Analyze()
|
||||||
{
|
{
|
||||||
|
// TODO: Replace by linq methods.
|
||||||
var messagesStat = (from item in context.TelemetryMessages
|
var messagesStat = (from item in context.TelemetryMessages
|
||||||
where item.IdTelemetry == idTelemetry
|
where item.IdTelemetry == idTelemetry
|
||||||
group item.DateTime by item.IdTelemetry into g
|
group item.DateTime by item.IdTelemetry into g
|
||||||
|
62
AsbCloudInfrastructure/Repository/CacheBase.cs
Normal file
62
AsbCloudInfrastructure/Repository/CacheBase.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Repository
|
||||||
|
{
|
||||||
|
#nullable enable
|
||||||
|
public class CacheBase<TEntity> : QueryContainer<TEntity>
|
||||||
|
where TEntity : class, AsbCloudDb.Model.IId
|
||||||
|
{
|
||||||
|
protected readonly IMemoryCache memoryCache;
|
||||||
|
protected string CacheTag = typeof(TEntity).Name;
|
||||||
|
protected TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
public CacheBase(IAsbCloudDbContext context, IMemoryCache memoryCache)
|
||||||
|
: base(context)
|
||||||
|
{
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheBase(IAsbCloudDbContext context, IMemoryCache memoryCache, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
|
: base(context, makeQuery)
|
||||||
|
{
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void DropCache()
|
||||||
|
=> memoryCache.Remove(CacheTag);
|
||||||
|
|
||||||
|
protected virtual IEnumerable<TEntity> GetCache()
|
||||||
|
{
|
||||||
|
var cache = memoryCache.GetOrCreate(CacheTag, cacheEntry =>
|
||||||
|
{
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
|
||||||
|
var entities = this.GetQuery().ToArray();
|
||||||
|
return entities;
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task<IEnumerable<TEntity>> GetCacheAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
var cache = memoryCache.GetOrCreateAsync(CacheTag, async (cacheEntry) =>
|
||||||
|
{
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
|
||||||
|
var entities = await this.GetQuery().ToArrayAsync(token);
|
||||||
|
return entities.AsEnumerable();
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
114
AsbCloudInfrastructure/Repository/CrudCacheRepositoryBase.cs
Normal file
114
AsbCloudInfrastructure/Repository/CrudCacheRepositoryBase.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
using AsbCloudApp.Services;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Repository
|
||||||
|
{
|
||||||
|
#nullable enable
|
||||||
|
/// <summary>
|
||||||
|
/// CRUD ñåðâèñ ñ êåøåì â îïåðàòèâêå
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TDto"></typeparam>
|
||||||
|
/// <typeparam name="TEntity"></typeparam>
|
||||||
|
public class CrudCacheRepositoryBase<TDto, TEntity> : CacheBase<TEntity>, ICrudRepository<TDto>
|
||||||
|
where TDto : AsbCloudApp.Data.IId
|
||||||
|
where TEntity : class, IId
|
||||||
|
{
|
||||||
|
protected int KeySelector(TEntity entity) => entity.Id;
|
||||||
|
protected readonly ICrudRepository<TDto> crudServiceBase;
|
||||||
|
|
||||||
|
public CrudCacheRepositoryBase(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
||||||
|
: base(dbContext, memoryCache)
|
||||||
|
{
|
||||||
|
crudServiceBase = new CrudRepositoryBase<TDto, TEntity>(dbContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrudCacheRepositoryBase(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
|
: base(dbContext, memoryCache, makeQuery)
|
||||||
|
{
|
||||||
|
crudServiceBase = new CrudRepositoryBase<TDto, TEntity>(dbContext, makeQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<int> InsertAsync(TDto newItem, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await crudServiceBase.InsertAsync(newItem, token);
|
||||||
|
if (result > 0)
|
||||||
|
DropCache();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<int> InsertRangeAsync(IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await crudServiceBase.InsertRangeAsync(dtos, token);
|
||||||
|
if (result > 0)
|
||||||
|
DropCache();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<int> UpdateAsync(TDto dto, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await crudServiceBase.UpdateAsync(dto, token);
|
||||||
|
if (result > 0)
|
||||||
|
DropCache();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
var cache = await GetCacheAsync(token);
|
||||||
|
var dtos = cache.Select(Convert);
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ñèíõðîííî ïîëó÷èòü çàïèñü ïî ÈÄ
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TDto? GetOrDefault(int id)
|
||||||
|
{
|
||||||
|
var cache = GetCache();
|
||||||
|
var cacheItem = cache.FirstOrDefault(d => d.Id == id);
|
||||||
|
if (cacheItem is null)
|
||||||
|
return default;
|
||||||
|
var dto = Convert(cacheItem);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token)
|
||||||
|
{
|
||||||
|
var cache = await GetCacheAsync(token);
|
||||||
|
var cacheItem = cache.FirstOrDefault(d => d.Id == id);
|
||||||
|
if (cacheItem is null)
|
||||||
|
return default;
|
||||||
|
var dto = Convert(cacheItem);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<int> DeleteAsync(int id, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await crudServiceBase.DeleteAsync(id, token);
|
||||||
|
if (result > 0)
|
||||||
|
DropCache();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual TDto Convert(TEntity src) => src.Adapt<TDto>();
|
||||||
|
|
||||||
|
protected virtual TEntity Convert(TDto src) => src.Adapt<TEntity>();
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
@ -1,140 +0,0 @@
|
|||||||
using AsbCloudDb.Model;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Repository
|
|
||||||
{
|
|
||||||
#nullable enable
|
|
||||||
/// <summary>
|
|
||||||
/// CRUD ñåðâèñ ñ êåøåì â îïåðàòèâêå
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TDto"></typeparam>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
public class CrudCacheServiceBase<TDto, TEntity> : CrudServiceBase<TDto, TEntity>
|
|
||||||
where TDto : AsbCloudApp.Data.IId
|
|
||||||
where TEntity : class, IId
|
|
||||||
{
|
|
||||||
protected string CacheTag = typeof(TDto).Name;
|
|
||||||
protected TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
|
||||||
private readonly IMemoryCache memoryCache;
|
|
||||||
|
|
||||||
protected int KeySelector(TEntity entity) => entity.Id;
|
|
||||||
|
|
||||||
public CrudCacheServiceBase(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
|
||||||
: base(dbContext)
|
|
||||||
{
|
|
||||||
this.memoryCache = memoryCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CrudCacheServiceBase(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
|
||||||
: base(dbContext, makeQuery)
|
|
||||||
{
|
|
||||||
this.memoryCache = memoryCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<int> InsertAsync(TDto newItem, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await base.InsertAsync(newItem, token);
|
|
||||||
if (result > 0)
|
|
||||||
DropCache();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<int> InsertRangeAsync(IEnumerable<TDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await base.InsertRangeAsync(dtos, token);
|
|
||||||
if (result > 0)
|
|
||||||
DropCache();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
var cache = await GetCacheAsync(token);
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ñèíõðîííî ïîëó÷èòü çàïèñü ïî ÈÄ
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override TDto? GetOrDefault(int id)
|
|
||||||
{
|
|
||||||
var cache = GetCache();
|
|
||||||
return cache.FirstOrDefault(d => d.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token)
|
|
||||||
{
|
|
||||||
var cache = await GetCacheAsync(token);
|
|
||||||
return cache.FirstOrDefault(d => d.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<int> UpdateAsync(TDto dto, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await base.UpdateAsync(dto, token);
|
|
||||||
if (result > 0)
|
|
||||||
DropCache();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<int> UpdateRangeAsync(IEnumerable<TDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await base.UpdateRangeAsync(dtos, token);
|
|
||||||
if (result > 0)
|
|
||||||
DropCache();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override async Task<int> DeleteAsync(int id, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await base.DeleteAsync(id, token);
|
|
||||||
if (result > 0)
|
|
||||||
DropCache();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual Task<IEnumerable<TDto>> GetCacheAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
var cache = memoryCache.GetOrCreateAsync(CacheTag, async (cacheEntry) => {
|
|
||||||
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
|
||||||
cacheEntry.SlidingExpiration = CacheOlescence;
|
|
||||||
|
|
||||||
var entities = await GetQuery().ToArrayAsync(token);
|
|
||||||
var dtos = entities.Select(Convert);
|
|
||||||
return dtos.ToArray().AsEnumerable();
|
|
||||||
});
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual IEnumerable<TDto> GetCache()
|
|
||||||
{
|
|
||||||
var cache = memoryCache.GetOrCreate(CacheTag, cacheEntry => {
|
|
||||||
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
|
||||||
cacheEntry.SlidingExpiration= CacheOlescence;
|
|
||||||
|
|
||||||
var entities = GetQuery().ToArray();
|
|
||||||
var dtos = entities.Select(Convert);
|
|
||||||
return dtos.ToArray();
|
|
||||||
});
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void DropCache()
|
|
||||||
=> memoryCache.Remove(CacheTag);
|
|
||||||
}
|
|
||||||
#nullable disable
|
|
||||||
}
|
|
@ -16,33 +16,22 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TDto"></typeparam>
|
/// <typeparam name="TDto"></typeparam>
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
/// <typeparam name="TEntity"></typeparam>
|
||||||
public class CrudServiceBase<TDto, TEntity> : ICrudService<TDto>
|
public class CrudRepositoryBase<TDto, TEntity> : QueryContainer<TEntity>, ICrudRepository<TDto>
|
||||||
where TDto : AsbCloudApp.Data.IId
|
where TDto : AsbCloudApp.Data.IId
|
||||||
where TEntity : class, IId
|
where TEntity : class, IId
|
||||||
{
|
{
|
||||||
protected readonly IAsbCloudDbContext dbContext;
|
public CrudRepositoryBase(IAsbCloudDbContext context)
|
||||||
protected readonly DbSet<TEntity> dbSet;
|
: base(context)
|
||||||
protected readonly Func<IQueryable<TEntity>> GetQuery;
|
{ }
|
||||||
|
|
||||||
public CrudServiceBase(IAsbCloudDbContext context)
|
public CrudRepositoryBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
{
|
: base(context, makeQuery)
|
||||||
dbContext = context;
|
{ }
|
||||||
dbSet = context.Set<TEntity>();
|
|
||||||
GetQuery = () => dbSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CrudServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
|
||||||
{
|
|
||||||
dbContext = context;
|
|
||||||
dbSet = context.Set<TEntity>();
|
|
||||||
GetQuery = () => makeQuery(dbSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token = default)
|
public virtual async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var entities = await GetQuery()
|
var entities = await GetQuery()
|
||||||
//.OrderBy(e => e.Id)
|
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.ToListAsync(token)
|
.ToListAsync(token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -117,7 +106,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (existingEntity is null)
|
if (existingEntity is null)
|
||||||
return ICrudService<TDto>.ErrorIdNotFound;
|
return ICrudRepository<TDto>.ErrorIdNotFound;
|
||||||
|
|
||||||
var entity = Convert(item);
|
var entity = Convert(item);
|
||||||
var entry = dbSet.Update(entity);
|
var entry = dbSet.Update(entity);
|
||||||
@ -126,29 +115,6 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return entry.Entity.Id;
|
return entry.Entity.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<int> UpdateRangeAsync(IEnumerable<TDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
var ids = dtos.Select(d => d.Id);
|
|
||||||
var existingEntities = await dbSet
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(d => ids.Contains(d.Id))
|
|
||||||
.Select(d => d.Id)
|
|
||||||
.ToListAsync(token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (ids.Count() > existingEntities.Count)
|
|
||||||
return ICrudService<TDto>.ErrorIdNotFound;
|
|
||||||
|
|
||||||
foreach (var dto in dtos)
|
|
||||||
{
|
|
||||||
var entity = Convert(dto);
|
|
||||||
var entry = dbSet.Update(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var affected = await dbContext.SaveChangesAsync(token);
|
|
||||||
return affected;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual Task<int> DeleteAsync(int id, CancellationToken token = default)
|
public virtual Task<int> DeleteAsync(int id, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
@ -156,7 +122,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.FirstOrDefault(e => e.Id == id);
|
.FirstOrDefault(e => e.Id == id);
|
||||||
if (entity == default)
|
if (entity == default)
|
||||||
return Task.FromResult(ICrudService<TDto>.ErrorIdNotFound);
|
return Task.FromResult(ICrudRepository<TDto>.ErrorIdNotFound);
|
||||||
var entry = dbSet.Remove(entity);
|
var entry = dbSet.Remove(entity);
|
||||||
var affected = dbContext.SaveChangesAsync(token);
|
var affected = dbContext.SaveChangesAsync(token);
|
||||||
entry.State = EntityState.Detached;
|
entry.State = EntityState.Detached;
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||||||
namespace AsbCloudInfrastructure.Repository
|
namespace AsbCloudInfrastructure.Repository
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public class CrudWellRelatedCacheServiceBase<TDto, TEntity> : CrudCacheServiceBase<TDto, TEntity>, IRepositoryWellRelated<TDto>
|
public class CrudWellRelatedCacheServiceBase<TDto, TEntity> : CrudCacheRepositoryBase<TDto, TEntity>, IRepositoryWellRelated<TDto>
|
||||||
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
||||||
where TEntity : class, IId, IWellRelated
|
where TEntity : class, IId, IWellRelated
|
||||||
{
|
{
|
||||||
@ -27,7 +27,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
|
|
||||||
var dtos = cache
|
var dtos = cache
|
||||||
.Where(e => e.IdWell == idWell)
|
.Where(e => e.IdWell == idWell)
|
||||||
.ToList();
|
.Select(Convert);
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
@ -41,7 +41,8 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
|
|
||||||
var dtos = cache
|
var dtos = cache
|
||||||
.Where(e => idsWells.Contains(e.IdWell))
|
.Where(e => idsWells.Contains(e.IdWell))
|
||||||
.ToList();
|
.Select(Convert);
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
|||||||
namespace AsbCloudInfrastructure.Repository
|
namespace AsbCloudInfrastructure.Repository
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public class CrudWellRelatedServiceBase<TDto, TEntity> : CrudServiceBase<TDto, TEntity>, IRepositoryWellRelated<TDto>
|
public class CrudWellRelatedServiceBase<TDto, TEntity> : CrudRepositoryBase<TDto, TEntity>, IRepositoryWellRelated<TDto>
|
||||||
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
||||||
where TEntity : class, IId, IWellRelated
|
where TEntity : class, IId, IWellRelated
|
||||||
{
|
{
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services;
|
|
||||||
using DocumentFormat.OpenXml.Drawing.Charts;
|
|
||||||
using DocumentFormat.OpenXml.Wordprocessing;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Org.BouncyCastle.Asn1.Ocsp;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
28
AsbCloudInfrastructure/Repository/QueryContainer.cs
Normal file
28
AsbCloudInfrastructure/Repository/QueryContainer.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Repository
|
||||||
|
{
|
||||||
|
public class QueryContainer<TEntity> where TEntity : class, IId
|
||||||
|
{
|
||||||
|
protected readonly IAsbCloudDbContext dbContext;
|
||||||
|
protected readonly DbSet<TEntity> dbSet;
|
||||||
|
protected readonly Func<IQueryable<TEntity>> GetQuery;
|
||||||
|
|
||||||
|
public QueryContainer(IAsbCloudDbContext context)
|
||||||
|
{
|
||||||
|
dbContext = context;
|
||||||
|
dbSet = context.Set<TEntity>();
|
||||||
|
GetQuery = () => dbSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryContainer(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
|
{
|
||||||
|
dbContext = context;
|
||||||
|
dbSet = context.Set<TEntity>();
|
||||||
|
GetQuery = () => makeQuery(dbSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,10 @@ using AsbCloudDb.Model;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Repository
|
namespace AsbCloudInfrastructure.Repository
|
||||||
{
|
{
|
||||||
@ -18,6 +22,29 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual async Task<int> UpdateRangeAsync(IEnumerable<SetpointsRequestDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
var ids = dtos.Select(d => d.Id);
|
||||||
|
var existingEntities = await dbSet
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(d => ids.Contains(d.Id))
|
||||||
|
.Select(d => d.Id)
|
||||||
|
.ToListAsync(token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (ids.Count() > existingEntities.Count)
|
||||||
|
return ICrudRepository<SetpointsRequestDto>.ErrorIdNotFound;
|
||||||
|
|
||||||
|
foreach (var dto in dtos)
|
||||||
|
{
|
||||||
|
var entity = Convert(dto);
|
||||||
|
var entry = dbSet.Update(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
var affected = await dbContext.SaveChangesAsync(token);
|
||||||
|
return affected;
|
||||||
|
}
|
||||||
|
|
||||||
protected override SetpointsRequestDto Convert(SetpointsRequest src)
|
protected override SetpointsRequestDto Convert(SetpointsRequest src)
|
||||||
{
|
{
|
||||||
var result = base.Convert(src);
|
var result = base.Convert(src);
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -268,7 +268,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
|||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DetectedOperationDto Convert(DetectedOperation operation, WellDto well, IEnumerable<OperationValueDto> operationValues, IEnumerable<ScheduleDto> schedules)
|
private static DetectedOperationDto Convert(DetectedOperation operation, WellDto well, IEnumerable<OperationValueDto> operationValues, IEnumerable<ScheduleDto> schedules)
|
||||||
{
|
{
|
||||||
var dto = operation.Adapt<DetectedOperationDto>();
|
var dto = operation.Adapt<DetectedOperationDto>();
|
||||||
dto.IdWell = well.Id;
|
dto.IdWell = well.Id;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -9,14 +7,16 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.DetectOperations
|
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public class OperationDetectionBackgroundService : BackgroundService
|
public static class OperationDetectionWorkFactory
|
||||||
{
|
{
|
||||||
private readonly string connectionString;
|
private const string workId = "Operation detection";
|
||||||
private readonly TimeSpan period = TimeSpan.FromHours(1);
|
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
|
||||||
|
|
||||||
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
|
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
|
||||||
{
|
{
|
||||||
@ -31,49 +31,18 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
|||||||
new DetectorTemplatingWhileDrilling(),
|
new DetectorTemplatingWhileDrilling(),
|
||||||
};
|
};
|
||||||
|
|
||||||
public OperationDetectionBackgroundService(IConfiguration configuration)
|
public static WorkPeriodic MakeWork()
|
||||||
{
|
{
|
||||||
connectionString = configuration.GetConnectionString("DefaultConnection");
|
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod);
|
||||||
|
workPeriodic.Timeout = TimeSpan.FromMinutes(30);
|
||||||
|
return workPeriodic;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken token = default)
|
// TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
|
||||||
|
private static async Task WorkAction(string _, IServiceProvider serviceProvider, CancellationToken token)
|
||||||
{
|
{
|
||||||
var timeToStartAnalysis = DateTime.Now;
|
using var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
|
||||||
.UseNpgsql(connectionString)
|
|
||||||
.Options;
|
|
||||||
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
if (DateTime.Now > timeToStartAnalysis)
|
|
||||||
{
|
|
||||||
timeToStartAnalysis = DateTime.Now + period;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var context = new AsbCloudDbContext(options);
|
|
||||||
var added = await DetectedAllTelemetriesAsync(context, token);
|
|
||||||
Trace.TraceInformation($"Total detection complete. Added {added} operations.");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.TraceError(ex.Message);
|
|
||||||
}
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
var ms = (int)(timeToStartAnalysis - DateTime.Now).TotalMilliseconds;
|
|
||||||
ms = ms > 100 ? ms : 100;
|
|
||||||
await Task.Delay(ms, token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task StopAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
await base.StopAsync(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<int> DetectedAllTelemetriesAsync(IAsbCloudDbContext db, CancellationToken token)
|
|
||||||
{
|
|
||||||
var lastDetectedDates = await db.DetectedOperations
|
var lastDetectedDates = await db.DetectedOperations
|
||||||
.GroupBy(o => o.IdTelemetry)
|
.GroupBy(o => o.IdTelemetry)
|
||||||
.Select(g => new
|
.Select(g => new
|
||||||
@ -88,7 +57,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
|||||||
.Select(t => t.Id)
|
.Select(t => t.Id)
|
||||||
.ToListAsync(token);
|
.ToListAsync(token);
|
||||||
|
|
||||||
var JounedlastDetectedDates = telemetryIds
|
var joinedlastDetectedDates = telemetryIds
|
||||||
.GroupJoin(lastDetectedDates,
|
.GroupJoin(lastDetectedDates,
|
||||||
t => t,
|
t => t,
|
||||||
o => o.IdTelemetry,
|
o => o.IdTelemetry,
|
||||||
@ -97,8 +66,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
|||||||
IdTelemetry = outer,
|
IdTelemetry = outer,
|
||||||
inner.SingleOrDefault()?.LastDate,
|
inner.SingleOrDefault()?.LastDate,
|
||||||
});
|
});
|
||||||
|
|
||||||
var affected = 0;
|
var affected = 0;
|
||||||
foreach (var item in JounedlastDetectedDates)
|
foreach (var item in joinedlastDetectedDates)
|
||||||
{
|
{
|
||||||
var stopwatch = Stopwatch.StartNew();
|
var stopwatch = Stopwatch.StartNew();
|
||||||
var newOperations = await DetectOperationsAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
var newOperations = await DetectOperationsAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
||||||
@ -109,7 +79,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
|||||||
affected += await db.SaveChangesAsync(token);
|
affected += await db.SaveChangesAsync(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return affected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
private static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
|||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public class DrillParamsService : CrudServiceBase<DrillParamsDto, DrillParams>, IDrillParamsService
|
public class DrillParamsService : CrudRepositoryBase<DrillParamsDto, DrillParams>, IDrillParamsService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
@ -3,10 +3,11 @@ using AsbCloudApp.Exceptions;
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Background;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -16,6 +17,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||||
{
|
{
|
||||||
|
# nullable enable
|
||||||
public class DrillingProgramService : IDrillingProgramService
|
public class DrillingProgramService : IDrillingProgramService
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, DrillingProgramCreateError> drillingProgramCreateErrors = new Dictionary<string, DrillingProgramCreateError>();
|
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 IUserRepository userRepository;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly IConfiguration configuration;
|
private readonly IConfiguration configuration;
|
||||||
private readonly IBackgroundWorkerService backgroundWorker;
|
private readonly BackgroundWorker backgroundWorker;
|
||||||
private readonly IEmailService emailService;
|
private readonly IEmailService emailService;
|
||||||
private readonly string connectionString;
|
|
||||||
|
|
||||||
private const int idFileCategoryDrillingProgram = 1000;
|
private const int idFileCategoryDrillingProgram = 1000;
|
||||||
private const int idFileCategoryDrillingProgramPartsStart = 1001;
|
private const int idFileCategoryDrillingProgramPartsStart = 1001;
|
||||||
@ -55,7 +56,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
IWellService wellService,
|
IWellService wellService,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
IBackgroundWorkerService backgroundWorker,
|
BackgroundWorker backgroundWorker,
|
||||||
IEmailService emailService)
|
IEmailService emailService)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -64,7 +65,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.backgroundWorker = backgroundWorker;
|
this.backgroundWorker = backgroundWorker;
|
||||||
this.connectionString = configuration.GetConnectionString("DefaultConnection");
|
|
||||||
this.emailService = emailService;
|
this.emailService = emailService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
{
|
{
|
||||||
Parts = parts,
|
Parts = parts,
|
||||||
Program = files.FirstOrDefault(f => f.IdCategory == idFileCategoryDrillingProgram)
|
Program = files.FirstOrDefault(f => f.IdCategory == idFileCategoryDrillingProgram)
|
||||||
.Adapt<FileInfoDto>(),
|
?.Adapt<FileInfoDto>(),
|
||||||
PermissionToEdit = userRepository.HasPermission(idUser, "DrillingProgram.edit"),
|
PermissionToEdit = userRepository.HasPermission(idUser, "DrillingProgram.edit"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
else
|
else
|
||||||
state.IdState = idStateNotInitialized;
|
state.IdState = idStateNotInitialized;
|
||||||
|
|
||||||
await TryEnqueueMakeProgramAsync(idWell, state, token);
|
await EnqueueMakeProgramWorkAsync(idWell, state, token);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.FirstOrDefaultAsync(p => p.IdWell == fileInfo.IdWell && p.IdFileCategory == fileInfo.IdCategory, token);
|
.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)
|
if (user is null)
|
||||||
throw new ForbidException($"User {idUser} is not in the approvers list.");
|
throw new ForbidException($"User {idUser} is not in the approvers list.");
|
||||||
|
|
||||||
@ -323,11 +323,11 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// если все согласованты согласовали - оповещаем публикатора
|
// если все согласованты согласовали - оповещаем публикатора
|
||||||
var approvers = part.RelatedUsers
|
var approvers = part!.RelatedUsers
|
||||||
.Where(u => u.IdUserRole == idUserRoleApprover);
|
.Where(u => u.IdUserRole == idUserRoleApprover);
|
||||||
if (approvers
|
if (approvers
|
||||||
.All(user => fileInfo.FileMarks
|
.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)))
|
(fileMarkDto.IdMarkType == idMarkTypeApprove && user.IdUser == idUser)))
|
||||||
{
|
{
|
||||||
await NotifyPublisherOnFullAccepAsync(fileMarkDto, token);
|
await NotifyPublisherOnFullAccepAsync(fileMarkDto, token);
|
||||||
@ -359,7 +359,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token)
|
private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token)
|
||||||
{
|
{
|
||||||
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, 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 user = file.Author;
|
||||||
var factory = new DrillingMailBodyFactory(configuration);
|
var factory = new DrillingMailBodyFactory(configuration);
|
||||||
var subject = factory.MakeSubject(well, "Загруженный вами документ полностью согласован");
|
var subject = factory.MakeSubject(well, "Загруженный вами документ полностью согласован");
|
||||||
@ -371,7 +371,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
||||||
{
|
{
|
||||||
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, 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 user = file.Author;
|
||||||
var factory = new DrillingMailBodyFactory(configuration);
|
var factory = new DrillingMailBodyFactory(configuration);
|
||||||
var subject = factory.MakeSubject(well, "Загруженный вами документ отклонен");
|
var subject = factory.MakeSubject(well, "Загруженный вами документ отклонен");
|
||||||
@ -405,12 +405,12 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
emailService.EnqueueSend(user.Email, subject, body);
|
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
|
var part = new DrillingProgramPartDto
|
||||||
{
|
{
|
||||||
IdFileCategory = partEntity.IdFileCategory,
|
IdFileCategory = partEntity.IdFileCategory,
|
||||||
Name = fileCategories.FirstOrDefault(c => c.Id == partEntity.IdFileCategory).Name,
|
Name = fileCategories.FirstOrDefault(c => c.Id == partEntity.IdFileCategory)!.Name,
|
||||||
Approvers = partEntity.RelatedUsers
|
Approvers = partEntity.RelatedUsers
|
||||||
.Where(r => r.IdUserRole == idUserRoleApprover)
|
.Where(r => r.IdUserRole == idUserRoleApprover)
|
||||||
.Select(r => r.User.Adapt<UserDto>()),
|
.Select(r => r.User.Adapt<UserDto>()),
|
||||||
@ -464,31 +464,27 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
return part;
|
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)
|
if (state.IdState == idStateCreating)
|
||||||
{
|
{
|
||||||
var workId = MakeWorkId(idWell);
|
var workId = MakeWorkId(idWell);
|
||||||
if (!backgroundWorker.Contains(workId))
|
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 resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.xlsx";
|
||||||
var tempResultFilePath = Path.Combine(Path.GetTempPath(), "drillingProgram", resultFileName);
|
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>()
|
var context = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
.UseNpgsql(connectionString)
|
var fileService = serviceProvider.GetRequiredService<FileService>();
|
||||||
.Options;
|
|
||||||
using var context = new AsbCloudDbContext(contextOptions);
|
|
||||||
var fileRepository = new FileRepository(context);
|
|
||||||
var fileStorageRepository = new FileStorageRepository();
|
|
||||||
var fileService = new FileService(fileRepository, fileStorageRepository);
|
|
||||||
var files = state.Parts.Select(p => fileService.GetUrl(p.File));
|
var files = state.Parts.Select(p => fileService.GetUrl(p.File));
|
||||||
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well);
|
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well);
|
||||||
await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token);
|
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}";
|
var message = $"Не удалось сформировать программу бурения по скважине {well?.Caption}";
|
||||||
drillingProgramCreateErrors[workId] = new()
|
drillingProgramCreateErrors[workId] = new()
|
||||||
@ -497,9 +493,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
Exception = exception.Message,
|
Exception = exception.Message,
|
||||||
};
|
};
|
||||||
return Task.CompletedTask;
|
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)
|
private async Task<int> RemoveDrillingProgramAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var workId = MakeWorkId(idWell);
|
var workId = MakeWorkId(idWell);
|
||||||
backgroundWorker.TryRemove(workId);
|
backgroundWorker.Delete(workId);
|
||||||
|
|
||||||
var filesIds = await context.Files
|
var filesIds = await context.Files
|
||||||
.Where(f => f.IdWell == idWell &&
|
.Where(f => f.IdWell == idWell &&
|
||||||
@ -529,4 +531,5 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
private static string MakeWorkId(int idWell)
|
private static string MakeWorkId(int idWell)
|
||||||
=> $"Make drilling program for wellId {idWell}";
|
=> $"Make drilling program for wellId {idWell}";
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
@ -8,26 +8,28 @@ using System.Linq;
|
|||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public class EmailService : IEmailService
|
public class EmailService : IEmailService
|
||||||
{
|
{
|
||||||
private readonly IBackgroundWorkerService backgroundWorker;
|
private readonly BackgroundWorker backgroundWorker;
|
||||||
private readonly bool IsConfigured;
|
private readonly bool IsConfigured;
|
||||||
private readonly string sender;
|
private readonly string sender;
|
||||||
private readonly string smtpServer;
|
private readonly string smtpServer;
|
||||||
private readonly string smtpPassword;
|
private readonly string smtpPassword;
|
||||||
|
|
||||||
public EmailService(IBackgroundWorkerService backgroundWorker, IConfiguration configuration)
|
public EmailService(BackgroundWorker backgroundWorker, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
sender = configuration.GetValue<string>("email:sender", null);
|
sender = configuration.GetValue("email:sender", string.Empty);
|
||||||
smtpPassword = configuration.GetValue<string>("email:password", null);
|
smtpPassword = configuration.GetValue("email:password", string.Empty);
|
||||||
smtpServer = configuration.GetValue<string>("email:smtpServer", null);
|
smtpServer = configuration.GetValue("email:smtpServer", string.Empty);
|
||||||
|
|
||||||
var configError = (string.IsNullOrEmpty(sender) ||
|
var configError = string.IsNullOrEmpty(sender) ||
|
||||||
string.IsNullOrEmpty(smtpPassword) ||
|
string.IsNullOrEmpty(smtpPassword) ||
|
||||||
string.IsNullOrEmpty(smtpServer));
|
string.IsNullOrEmpty(smtpServer);
|
||||||
|
|
||||||
IsConfigured = !configError;
|
IsConfigured = !configError;
|
||||||
|
|
||||||
@ -44,20 +46,21 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
Trace.TraceWarning("smtp is not configured");
|
Trace.TraceWarning("smtp is not configured");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var jobId = CalcJobId(addresses, subject, htmlBody);
|
var workId = MakeWorkId(addresses, subject, htmlBody);
|
||||||
if (!backgroundWorker.Contains(jobId))
|
if (!backgroundWorker.Contains(workId))
|
||||||
{
|
{
|
||||||
var action = MakeEmailSendJobAsync(addresses, subject, htmlBody);
|
var workAction = MakeEmailSendWorkAction(addresses, subject, htmlBody);
|
||||||
backgroundWorker.Enqueue(jobId, action);
|
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>();
|
var mailAddresses = new List<MailAddress>();
|
||||||
foreach (var address in addresses)
|
foreach (var address in addresses)
|
||||||
{
|
{
|
||||||
if (MailAddress.TryCreate(address, out MailAddress mailAddress))
|
if (MailAddress.TryCreate(address, out MailAddress? mailAddress))
|
||||||
mailAddresses.Add(mailAddress);
|
mailAddresses.Add(mailAddress);
|
||||||
else
|
else
|
||||||
Trace.TraceWarning($"Mail {address} is not correct.");
|
Trace.TraceWarning($"Mail {address} is not correct.");
|
||||||
@ -69,16 +72,16 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
if (string.IsNullOrEmpty(subject))
|
if (string.IsNullOrEmpty(subject))
|
||||||
throw new ArgumentInvalidException($"{nameof(subject)} should be set", nameof(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 from = new MailAddress(sender);
|
||||||
|
var message = new MailMessage
|
||||||
var message = new MailMessage();
|
{
|
||||||
message.From = from;
|
From = from
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var mailAddress in mailAddresses)
|
foreach (var mailAddress in mailAddresses)
|
||||||
message.To.Add(mailAddress);
|
message.To.Add(mailAddress);
|
||||||
//message.To.Add("support@digitaldrilling.ru");
|
|
||||||
|
|
||||||
message.BodyEncoding = System.Text.Encoding.UTF8;
|
message.BodyEncoding = System.Text.Encoding.UTF8;
|
||||||
message.Body = htmlBody;
|
message.Body = htmlBody;
|
||||||
@ -91,12 +94,12 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
||||||
|
|
||||||
await client.SendMailAsync(message, token);
|
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);
|
var hash = GetHashCode(addresses);
|
||||||
hash ^= subject.GetHashCode();
|
hash ^= subject.GetHashCode();
|
||||||
@ -114,4 +117,5 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
public class FileCategoryService : CrudCacheServiceBase<FileCategoryDto, FileCategory>, IFileCategoryService
|
public class FileCategoryService : CrudCacheRepositoryBase<FileCategoryDto, FileCategory>, IFileCategoryService
|
||||||
{
|
{
|
||||||
public FileCategoryService(IAsbCloudDbContext context, IMemoryCache memoryCache)
|
public FileCategoryService(IAsbCloudDbContext context, IMemoryCache memoryCache)
|
||||||
: base(context, memoryCache) { }
|
: base(context, memoryCache) { }
|
||||||
@ -22,7 +22,8 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
var dtos = cache
|
var dtos = cache
|
||||||
.Where(f => f.Id >= 10000)
|
.Where(f => f.Id >= 10000)
|
||||||
.Where(f => f.Id <= 20000);
|
.Where(f => f.Id <= 20000)
|
||||||
|
.Select(Convert);
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,37 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
internal class LimitingParameterBackgroundService : BackgroundService
|
internal static class LimitingParameterCalcWorkFactory
|
||||||
{
|
{
|
||||||
private readonly string connectionString;
|
private const string workId = "Limiting parameter calc";
|
||||||
private readonly TimeSpan period = TimeSpan.FromHours(1);
|
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
|
||||||
|
|
||||||
public LimitingParameterBackgroundService(IConfiguration configuration)
|
public static WorkPeriodic MakeWork()
|
||||||
{
|
{
|
||||||
connectionString = configuration.GetConnectionString("DefaultConnection");
|
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod)
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
var timeToStart = DateTime.Now;
|
|
||||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
|
||||||
.UseNpgsql(connectionString)
|
|
||||||
.Options;
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
if (DateTime.Now > timeToStart)
|
Timeout = TimeSpan.FromMinutes(30)
|
||||||
{
|
};
|
||||||
timeToStart = DateTime.Now + period;
|
return workPeriodic;
|
||||||
try
|
|
||||||
{
|
|
||||||
using var context = new AsbCloudDbContext(options);
|
|
||||||
var added = await LimitingParameterAsync(context, token);
|
|
||||||
Trace.TraceInformation($"Total limiting parameter complete. Added {added} limiting parameters.");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.TraceError(ex.Message);
|
|
||||||
}
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
var ms = (int)(timeToStart - DateTime.Now).TotalMilliseconds;
|
|
||||||
ms = ms > 100 ? ms : 100;
|
|
||||||
await Task.Delay(ms, token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<int> LimitingParameterAsync(IAsbCloudDbContext context, CancellationToken token)
|
// TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
|
||||||
|
private static async Task WorkAction(string _, IServiceProvider serviceProvider, CancellationToken token)
|
||||||
{
|
{
|
||||||
var lastDetectedDates = await context.LimitingParameter
|
using var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
|
var lastDetectedDates = await db.LimitingParameter
|
||||||
.GroupBy(o => o.IdTelemetry)
|
.GroupBy(o => o.IdTelemetry)
|
||||||
.Select(g => new
|
.Select(g => new
|
||||||
{
|
{
|
||||||
@ -64,7 +40,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
})
|
})
|
||||||
.ToListAsync(token);
|
.ToListAsync(token);
|
||||||
|
|
||||||
var telemetryIds = await context.Telemetries
|
var telemetryIds = await db.Telemetries
|
||||||
.Where(t => t.Info != null && t.TimeZone != null)
|
.Where(t => t.Info != null && t.TimeZone != null)
|
||||||
.Select(t => t.Id)
|
.Select(t => t.Id)
|
||||||
.ToListAsync(token);
|
.ToListAsync(token);
|
||||||
@ -79,17 +55,15 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
inner.SingleOrDefault()?.LastDate,
|
inner.SingleOrDefault()?.LastDate,
|
||||||
});
|
});
|
||||||
|
|
||||||
var affected = 0;
|
|
||||||
foreach (var item in telemetryLastDetectedDates)
|
foreach (var item in telemetryLastDetectedDates)
|
||||||
{
|
{
|
||||||
var newLimitingParameters = await GetLimitingParameterAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, context, token);
|
var newLimitingParameters = await GetLimitingParameterAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
||||||
if (newLimitingParameters?.Any() == true)
|
if (newLimitingParameters?.Any() == true)
|
||||||
{
|
{
|
||||||
context.LimitingParameter.AddRange(newLimitingParameters);
|
db.LimitingParameter.AddRange(newLimitingParameters);
|
||||||
affected += await context.SaveChangesAsync(token);
|
await db.SaveChangesAsync(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return affected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IEnumerable<LimitingParameter>> GetLimitingParameterAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
private static async Task<IEnumerable<LimitingParameter>> GetLimitingParameterAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
||||||
|
@ -15,7 +15,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
{
|
{
|
||||||
private readonly ILimitingParameterRepository limitingParameterRepository;
|
private readonly ILimitingParameterRepository limitingParameterRepository;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly Dictionary<int, string> feedRegulatorData = new Dictionary<int, string>()
|
private readonly Dictionary<int, string> feedRegulatorData = new ()
|
||||||
{
|
{
|
||||||
{ 0, "Нет ограничения" },
|
{ 0, "Нет ограничения" },
|
||||||
{ 1, "МСП" },
|
{ 1, "МСП" },
|
||||||
@ -63,6 +63,11 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Dictionary<int, string> GetLimitingParameteraNames() //TODO: Перенести получение ограничений в репозиторий
|
||||||
|
{
|
||||||
|
return feedRegulatorData;
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<LimitingParameterDataDto> TrimLimitingParameters(IEnumerable<LimitingParameterDataDto> data, LimitingParameterRequest request)
|
private IEnumerable<LimitingParameterDataDto> TrimLimitingParameters(IEnumerable<LimitingParameterDataDto> data, LimitingParameterRequest request)
|
||||||
{
|
{
|
||||||
var result = data.Select((x) =>
|
var result = data.Select((x) =>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Background;
|
||||||
using AsbSaubReport;
|
using AsbSaubReport;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -15,30 +15,32 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public class ReportService : IReportService
|
public class ReportService : IReportService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly string connectionString;
|
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly IBackgroundWorkerService backgroundWorkerService;
|
private readonly BackgroundWorker 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ReportCategoryId { get; private set; }
|
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)
|
DateTime end, Action<object, string> progressHandler)
|
||||||
{
|
{
|
||||||
var timezoneOffset = wellService.GetTimezone(idWell).Hours;
|
var timezoneOffset = wellService.GetTimezone(idWell).Hours;
|
||||||
@ -47,12 +49,12 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
var beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset);
|
var beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset);
|
||||||
var endRemote = end.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>()
|
using var context = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
.UseNpgsql(connectionString)
|
var fileService = serviceProvider.GetRequiredService<FileService>();
|
||||||
.Options;
|
|
||||||
using var context = new AsbCloudDbContext(contextOptions);
|
|
||||||
|
|
||||||
var tempDir = Path.Combine(Path.GetTempPath(), "report");
|
var tempDir = Path.Combine(Path.GetTempPath(), "report");
|
||||||
|
|
||||||
@ -66,10 +68,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
};
|
};
|
||||||
generator.Make(reportFileName);
|
generator.Make(reportFileName);
|
||||||
|
|
||||||
var fileRepository = new FileRepository(context);
|
var fileInfo = (await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token))!;
|
||||||
var fileStorageRepository = new FileStorageRepository();
|
|
||||||
var fileService = new FileService(fileRepository, fileStorageRepository);
|
|
||||||
var fileInfo = await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token);
|
|
||||||
|
|
||||||
progressHandler.Invoke(new
|
progressHandler.Invoke(new
|
||||||
{
|
{
|
||||||
@ -91,13 +90,17 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
};
|
};
|
||||||
context.ReportProperties.Add(newReportProperties);
|
context.ReportProperties.Add(newReportProperties);
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
});
|
};
|
||||||
|
|
||||||
|
var work = new WorkBase(workId, workAction);
|
||||||
|
backgroundWorkerService.Push(work);
|
||||||
|
|
||||||
progressHandler.Invoke(new ReportProgressDto
|
progressHandler.Invoke(new ReportProgressDto
|
||||||
{
|
{
|
||||||
Operation = "Ожидает начала в очереди.",
|
Operation = "Ожидает начала в очереди.",
|
||||||
Progress = 0f,
|
Progress = 0f,
|
||||||
}, newReportId);
|
}, workId);
|
||||||
return newReportId;
|
return workId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetReportPagesCount(int idWell, DateTime begin, DateTime end, int stepSeconds, int format)
|
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 beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset);
|
||||||
var endRemote = end.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();
|
var pagesCount = generator.GetPagesCount();
|
||||||
return pagesCount;
|
return pagesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatesRangeDto GetDatesRangeOrDefault(int idWell)
|
public DatesRangeDto? GetDatesRangeOrDefault(int idWell)
|
||||||
{
|
{
|
||||||
var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
|
var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
|
||||||
if (idTelemetry is null)
|
if (idTelemetry is null)
|
||||||
@ -128,8 +131,8 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.OrderBy(o => o.File.UploadDate)
|
.OrderBy(o => o.File.UploadDate)
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Take(1024);
|
.Take(1024);
|
||||||
var properties = await propertiesQuery.ToListAsync(token);
|
var entities = await propertiesQuery.ToListAsync(token);
|
||||||
return properties.Select(p => new ReportPropertiesDto
|
var dtos = entities.Select(p => new ReportPropertiesDto
|
||||||
{
|
{
|
||||||
Id = p.Id,
|
Id = p.Id,
|
||||||
Name = p.File.Name,
|
Name = p.File.Name,
|
||||||
@ -151,10 +154,11 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
Step = p.Step,
|
Step = p.Step,
|
||||||
Format = p.Format == 0 ? ".pdf" : ".las"
|
Format = p.Format == 0 ? ".pdf" : ".las"
|
||||||
});
|
});
|
||||||
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReportGenerator GetReportGenerator(int idWell, DateTime begin,
|
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);
|
var dataSource = new ReportDataSourcePgCloud(context, idWell);
|
||||||
IReportGenerator generator = format switch
|
IReportGenerator generator = format switch
|
||||||
@ -173,4 +177,5 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
return generator;
|
return generator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public class TelemetryDataCache<TDto>
|
public class TelemetryDataCache<TDto>
|
||||||
where TDto : AsbCloudApp.Data.ITelemetryData
|
where TDto : AsbCloudApp.Data.ITelemetryData
|
||||||
{
|
{
|
||||||
private const int activeWellCapacity = 24 * 60 * 60;
|
private const int activeWellCapacity = 12 * 60 * 60;
|
||||||
private const int doneWellCapacity = 65 * 60;
|
private const int doneWellCapacity = 65 * 60;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<int, CyclycArray<TDto>> caches;
|
private readonly ConcurrentDictionary<int, CyclycArray<TDto>> caches;
|
||||||
|
@ -41,6 +41,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
public TelemetryTracker(IConfiguration configuration, IMemoryCache memoryCache)
|
public TelemetryTracker(IConfiguration configuration, IMemoryCache memoryCache)
|
||||||
{
|
{
|
||||||
|
// TODO: make this background work
|
||||||
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||||
.UseNpgsql(configuration.GetConnectionString("DefaultConnection"))
|
.UseNpgsql(configuration.GetConnectionString("DefaultConnection"))
|
||||||
.Options;
|
.Options;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudDb.Model.Subsystems;
|
using AsbCloudDb.Model.Subsystems;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
using AsbCloudInfrastructure.Services.Subsystems.Utils;
|
using AsbCloudInfrastructure.Services.Subsystems.Utils;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
@ -16,56 +16,30 @@ using System.Threading.Tasks;
|
|||||||
namespace AsbCloudInfrastructure.Services.Subsystems
|
namespace AsbCloudInfrastructure.Services.Subsystems
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
internal class SubsystemOperationTimeBackgroundService : BackgroundService
|
internal static class SubsystemOperationTimeCalcWorkFactory
|
||||||
{
|
{
|
||||||
private readonly string connectionString;
|
private const string workId = "Subsystem operation time calc";
|
||||||
private readonly TimeSpan period = TimeSpan.FromHours(1);
|
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;
|
||||||
private const int idSubsytemAkb = 1;
|
private const int idSubsytemAkb = 1;
|
||||||
private const int idSubsytemMse = 2;
|
private const int idSubsytemMse = 2;
|
||||||
|
|
||||||
public SubsystemOperationTimeBackgroundService(IConfiguration configuration)
|
public static WorkPeriodic MakeWork()
|
||||||
{
|
{
|
||||||
connectionString = configuration.GetConnectionString("DefaultConnection");
|
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod)
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
var timeToStart = DateTime.Now;
|
|
||||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
|
||||||
.UseNpgsql(connectionString)
|
|
||||||
.Options;
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
if (DateTime.Now > timeToStart)
|
Timeout = TimeSpan.FromMinutes(30)
|
||||||
{
|
};
|
||||||
timeToStart = DateTime.Now + period;
|
return workPeriodic;
|
||||||
try
|
|
||||||
{
|
|
||||||
using var context = new AsbCloudDbContext(options);
|
|
||||||
var added = await OperationTimeAllTelemetriesAsync(context, token);
|
|
||||||
Trace.TraceInformation($"Total subsystem operation time complete. Added {added} operations time.");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.TraceError(ex.Message);
|
|
||||||
}
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
var ms = (int)(timeToStart - DateTime.Now).TotalMilliseconds;
|
|
||||||
ms = ms > 100 ? ms : 100;
|
|
||||||
await Task.Delay(ms, token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task StopAsync(CancellationToken token)
|
// TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
|
||||||
|
private static async Task WorkAction(string _, IServiceProvider serviceProvider, CancellationToken token)
|
||||||
{
|
{
|
||||||
await base.StopAsync(token).ConfigureAwait(false);
|
using var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<int> OperationTimeAllTelemetriesAsync(IAsbCloudDbContext db, CancellationToken token)
|
|
||||||
{
|
|
||||||
var lastDetectedDates = await db.SubsystemOperationTimes
|
var lastDetectedDates = await db.SubsystemOperationTimes
|
||||||
.GroupBy(o => o.IdTelemetry)
|
.GroupBy(o => o.IdTelemetry)
|
||||||
.Select(g => new
|
.Select(g => new
|
||||||
@ -90,23 +64,21 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
|||||||
inner.SingleOrDefault()?.LastDate,
|
inner.SingleOrDefault()?.LastDate,
|
||||||
});
|
});
|
||||||
|
|
||||||
var affected = 0;
|
|
||||||
foreach (var item in telemetryLastDetectedDates)
|
foreach (var item in telemetryLastDetectedDates)
|
||||||
{
|
{
|
||||||
var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
||||||
if (newOperationsSaub?.Any() == true)
|
if (newOperationsSaub?.Any() == true)
|
||||||
{
|
{
|
||||||
db.SubsystemOperationTimes.AddRange(newOperationsSaub);
|
db.SubsystemOperationTimes.AddRange(newOperationsSaub);
|
||||||
affected += await db.SaveChangesAsync(token);
|
await db.SaveChangesAsync(token);
|
||||||
}
|
}
|
||||||
var newOperationsSpin = await OperationTimeSpinAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
var newOperationsSpin = await OperationTimeSpinAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
||||||
if (newOperationsSpin?.Any() == true)
|
if (newOperationsSpin?.Any() == true)
|
||||||
{
|
{
|
||||||
db.SubsystemOperationTimes.AddRange(newOperationsSpin);
|
db.SubsystemOperationTimes.AddRange(newOperationsSpin);
|
||||||
affected += await db.SaveChangesAsync(token);
|
await db.SaveChangesAsync(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return affected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<DbDataReader> ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
|
private static async Task<DbDataReader> ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
|
@ -23,13 +23,13 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
|||||||
|
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly ICrudService<SubsystemDto> subsystemService;
|
private readonly ICrudRepository<SubsystemDto> subsystemService;
|
||||||
private readonly IDetectedOperationService detectedOperationService;
|
private readonly IDetectedOperationService detectedOperationService;
|
||||||
public const int IdSubsystemAKB = 1;
|
public const int IdSubsystemAKB = 1;
|
||||||
public const int IdSubsystemMSE = 2;
|
public const int IdSubsystemMSE = 2;
|
||||||
public const int IdSubsystemSpin = 65536;
|
public const int IdSubsystemSpin = 65536;
|
||||||
public const int IdSubsystemTorque = 65537;
|
public const int IdSubsystemTorque = 65537;
|
||||||
public SubsystemOperationTimeService(IAsbCloudDbContext db, IWellService wellService, ICrudService<SubsystemDto> subsystemService, IDetectedOperationService detectedOperationService)
|
public SubsystemOperationTimeService(IAsbCloudDbContext db, IWellService wellService, ICrudRepository<SubsystemDto> subsystemService, IDetectedOperationService detectedOperationService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
|
@ -15,7 +15,7 @@ using System.Threading.Tasks;
|
|||||||
namespace AsbCloudInfrastructure.Services.Subsystems
|
namespace AsbCloudInfrastructure.Services.Subsystems
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
internal class SubsystemService : CrudCacheServiceBase<SubsystemDto, Subsystem>, ISubsystemService
|
internal class SubsystemService : CrudCacheRepositoryBase<SubsystemDto, Subsystem>, ISubsystemService
|
||||||
{
|
{
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
public SubsystemService(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, IWellService wellService) : base(dbContext, memoryCache)
|
public SubsystemService(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, IWellService wellService) : base(dbContext, memoryCache)
|
||||||
|
@ -15,13 +15,13 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
public class WellService : CrudCacheServiceBase<WellDto, Well>, IWellService
|
public class WellService : CrudCacheRepositoryBase<WellDto, Well>, IWellService
|
||||||
{
|
{
|
||||||
private const string relationCompaniesWellsCacheTag = "RelationCompaniesWells";
|
private const string relationCompaniesWellsCacheTag = "RelationCompaniesWells";
|
||||||
private static readonly TimeSpan relationCompaniesWellsCacheObsolence = TimeSpan.FromMinutes(15);
|
private static readonly TimeSpan relationCompaniesWellsCacheObsolence = TimeSpan.FromMinutes(15);
|
||||||
|
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
private readonly ICrudService<CompanyTypeDto> companyTypesService;
|
private readonly ICrudRepository<CompanyTypeDto> companyTypesService;
|
||||||
private readonly ITimezoneService timezoneService;
|
private readonly ITimezoneService timezoneService;
|
||||||
private readonly IWellOperationService wellOperationService;
|
private readonly IWellOperationService wellOperationService;
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
this.timezoneService = timezoneService;
|
this.timezoneService = timezoneService;
|
||||||
|
|
||||||
this.wellOperationService = new WellOperationService.WellOperationService(db, memoryCache, this);
|
this.wellOperationService = new WellOperationService.WellOperationService(db, memoryCache, this);
|
||||||
companyTypesService = new CrudCacheServiceBase<CompanyTypeDto, CompanyType>(dbContext, memoryCache);
|
companyTypesService = new CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>(dbContext, memoryCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<RelationCompanyWell> GetCacheRelationCompanyWell()
|
private IEnumerable<RelationCompanyWell> GetCacheRelationCompanyWell()
|
||||||
@ -81,9 +81,10 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.Select(r => r.IdWell);
|
.Select(r => r.IdWell);
|
||||||
|
|
||||||
var wellsDtos = (await GetCacheAsync(token))
|
var wellsDtos = (await GetCacheAsync(token))
|
||||||
.Where(w => wellsIds.Contains(w.Id));
|
.Where(w => wellsIds.Contains(w.Id))
|
||||||
|
.Select(Convert);
|
||||||
|
|
||||||
return wellsDtos.ToList();
|
return wellsDtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<int> InsertAsync(WellDto dto, CancellationToken token = default)
|
public override async Task<int> InsertAsync(WellDto dto, CancellationToken token = default)
|
||||||
@ -155,8 +156,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
|
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
|
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
|
||||||
var dto = Convert(entity);
|
return entity!.Caption;
|
||||||
return dto.Caption;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<CompanyDto>> GetCompaniesAsync(int idWell, CancellationToken token)
|
public async Task<IEnumerable<CompanyDto>> GetCompaniesAsync(int idWell, CancellationToken token)
|
||||||
|
@ -1,26 +1,72 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
|
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||||
|
using AsbCloudInfrastructure.Services.Subsystems;
|
||||||
|
using AsbCloudInfrastructure.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public static void BeforeRunHandler(IHost host, IConfigurationRoot configuration)
|
public static void BeforeRunHandler(IHost host)
|
||||||
{
|
{
|
||||||
using var scope = host.Services.CreateScope();
|
using var scope = host.Services.CreateScope();
|
||||||
var context = scope.ServiceProvider.GetService<IAsbCloudDbContext>();
|
var provider = scope.ServiceProvider;
|
||||||
context.Database.SetCommandTimeout(TimeSpan.FromSeconds(2 * 60));
|
|
||||||
|
|
||||||
|
var context = provider.GetService<IAsbCloudDbContext>();
|
||||||
|
context.Database.SetCommandTimeout(TimeSpan.FromSeconds(2 * 60));
|
||||||
context.Database.Migrate();
|
context.Database.Migrate();
|
||||||
|
|
||||||
var wellService = scope.ServiceProvider.GetService<IWellService>();
|
var wellService = provider.GetRequiredService<IWellService>();
|
||||||
wellService.EnshureTimezonesIsSetAsync(System.Threading.CancellationToken.None).Wait();
|
wellService.EnshureTimezonesIsSetAsync(CancellationToken.None).Wait();// TODO: make this background work
|
||||||
|
|
||||||
|
var backgroundWorker = provider.GetRequiredService<Background.BackgroundWorker>();
|
||||||
|
backgroundWorker.Push(OperationDetectionWorkFactory.MakeWork());
|
||||||
|
backgroundWorker.Push(SubsystemOperationTimeCalcWorkFactory.MakeWork());
|
||||||
|
backgroundWorker.Push(LimitingParameterCalcWorkFactory.MakeWork());
|
||||||
|
backgroundWorker.Push(MakeMemoryMonitoringWork());
|
||||||
|
|
||||||
|
Task.Delay(1_000)
|
||||||
|
.ContinueWith(async (_) => await backgroundWorker.StartAsync(CancellationToken.None));
|
||||||
|
}
|
||||||
|
|
||||||
|
static WorkPeriodic MakeMemoryMonitoringWork()
|
||||||
|
{
|
||||||
|
var workId = "Memory monitoring";
|
||||||
|
var workAction = (string _, IServiceProvider _, CancellationToken _) => {
|
||||||
|
var bytes = GC.GetTotalMemory(false);
|
||||||
|
var bytesString = FromatBytes(bytes);
|
||||||
|
System.Diagnostics.Trace.TraceInformation($"Total memory allocated is {bytesString} bytes. DbContext count is:{AsbCloudDb.Model.AsbCloudDbContext.ReferenceCount}");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
var workPeriod = TimeSpan.FromMinutes(1);
|
||||||
|
var work = new WorkPeriodic(workId, workAction, workPeriod);
|
||||||
|
return work;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string FromatBytes(long bytes)
|
||||||
|
{
|
||||||
|
const double gigaByte = 1024 * 1024 * 1024;
|
||||||
|
const double megaByte = 1024 * 1024;
|
||||||
|
const double kiloByte = 1024;
|
||||||
|
|
||||||
|
if (bytes > 10 * gigaByte)
|
||||||
|
return (bytes / gigaByte).ToString("### ### ###.## Gb");
|
||||||
|
|
||||||
|
if (bytes > 10 * megaByte)
|
||||||
|
return (bytes / megaByte).ToString("### ### ###.## Mb");
|
||||||
|
|
||||||
|
if (bytes > 10 * kiloByte)
|
||||||
|
return (bytes / megaByte).ToString("### ### ###.## Kb");
|
||||||
|
|
||||||
|
return bytes.ToString("### ### ###");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace AsbCloudWebApi.Tests
|
|||||||
{
|
{
|
||||||
public static Mock<TRepository> Make<TRepository, TDto>(ICollection<TDto> data)
|
public static Mock<TRepository> Make<TRepository, TDto>(ICollection<TDto> data)
|
||||||
where TDto : AsbCloudApp.Data.IId
|
where TDto : AsbCloudApp.Data.IId
|
||||||
where TRepository : class, ICrudService<TDto>
|
where TRepository : class, ICrudRepository<TDto>
|
||||||
{
|
{
|
||||||
var repositoryMock = new Mock<TRepository>();
|
var repositoryMock = new Mock<TRepository>();
|
||||||
|
|
||||||
|
@ -0,0 +1,244 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Moq;
|
||||||
|
using System;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.ServicesTests
|
||||||
|
{
|
||||||
|
public class BackgroundWorkerTest
|
||||||
|
{
|
||||||
|
private readonly Mock<IServiceProvider> mockServiceProvider;
|
||||||
|
private readonly Mock<IServiceScopeFactory> mockServiceScopeFactory;
|
||||||
|
private readonly Func<string, IServiceProvider, CancellationToken, Task> someAction = (string id, IServiceProvider scope, CancellationToken token) => Task.CompletedTask;
|
||||||
|
|
||||||
|
public BackgroundWorkerTest()
|
||||||
|
{
|
||||||
|
var mockServiceScope = new Mock<IServiceScope>();
|
||||||
|
mockServiceScopeFactory = new Mock<IServiceScopeFactory>();
|
||||||
|
mockServiceProvider = new Mock<IServiceProvider>();
|
||||||
|
|
||||||
|
mockServiceScope.SetReturnsDefault(mockServiceProvider.Object);
|
||||||
|
mockServiceProvider.SetReturnsDefault(mockServiceScopeFactory.Object);
|
||||||
|
mockServiceProvider.Setup(s => s.GetService(It.IsAny<Type>()))
|
||||||
|
.Returns(mockServiceScopeFactory.Object);
|
||||||
|
mockServiceScopeFactory.SetReturnsDefault(mockServiceScope.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Contains_returns_true()
|
||||||
|
{
|
||||||
|
mockServiceScopeFactory.Invocations.Clear();
|
||||||
|
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
const string work1Id = "long name 1";
|
||||||
|
const string work2Id = "long name 2";
|
||||||
|
|
||||||
|
var work1 = new WorkBase(work1Id, someAction);
|
||||||
|
var work2 = new WorkPeriodic(work2Id, someAction, TimeSpan.Zero);
|
||||||
|
|
||||||
|
BackgroundWorker.Push(work1);
|
||||||
|
BackgroundWorker.Push(work2);
|
||||||
|
|
||||||
|
Assert.True(BackgroundWorker.Contains(work1Id));
|
||||||
|
Assert.True(BackgroundWorker.Contains(work2Id));
|
||||||
|
Assert.False(BackgroundWorker.Contains(work2Id + work1Id));
|
||||||
|
Assert.False(BackgroundWorker.Contains(string.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Push_makes_new_scope_after_start()
|
||||||
|
{
|
||||||
|
mockServiceScopeFactory.Invocations.Clear();
|
||||||
|
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var work = new WorkBase("", someAction);
|
||||||
|
BackgroundWorker.Push(work);
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(10);
|
||||||
|
|
||||||
|
mockServiceScopeFactory.Verify(f => f.CreateScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Makes_primary_work_done()
|
||||||
|
{
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var workDone = false;
|
||||||
|
var work = new WorkBase("", (_, _, _) =>
|
||||||
|
{
|
||||||
|
workDone = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
BackgroundWorker.Push(work);
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(10);
|
||||||
|
|
||||||
|
Assert.True(workDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sets_ExecutionTime_after_work_done()
|
||||||
|
{
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var work = new WorkBase("", someAction);
|
||||||
|
BackgroundWorker.Push(work);
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(10);
|
||||||
|
|
||||||
|
Assert.True(work.ExecutionTime > TimeSpan.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Makes_periodic_work_done()
|
||||||
|
{
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var workDone = false;
|
||||||
|
var work = new WorkPeriodic("", (_, _, _) =>
|
||||||
|
{
|
||||||
|
workDone = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
TimeSpan.FromMilliseconds(10));
|
||||||
|
BackgroundWorker.Push(work);
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(20);
|
||||||
|
|
||||||
|
Assert.True(workDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Does_not_start_periodic_work()
|
||||||
|
{
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var workDone = false;
|
||||||
|
var work = new WorkPeriodic("", (_, _, _) =>
|
||||||
|
{
|
||||||
|
workDone = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
TimeSpan.FromSeconds(30))
|
||||||
|
{
|
||||||
|
LastStart = DateTime.Now
|
||||||
|
};
|
||||||
|
BackgroundWorker.Push(work);
|
||||||
|
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(20);
|
||||||
|
|
||||||
|
Assert.False(workDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Follows_work_priority()
|
||||||
|
{
|
||||||
|
var order = 0;
|
||||||
|
var work1Order = -1;
|
||||||
|
var work2Order = -1;
|
||||||
|
|
||||||
|
var work1 = new WorkPeriodic("1", (_, _, _) =>
|
||||||
|
{
|
||||||
|
work1Order = order++;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
TimeSpan.FromMilliseconds(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
var work2 = new WorkBase("2", (_, _, _) =>
|
||||||
|
{
|
||||||
|
work2Order = order++;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
BackgroundWorker.Push(work2);
|
||||||
|
BackgroundWorker.Push(work1);
|
||||||
|
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(2_100);
|
||||||
|
|
||||||
|
Assert.True(work2Order < work1Order);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Runs_second_after_delete_first()
|
||||||
|
{
|
||||||
|
var workDone = false;
|
||||||
|
|
||||||
|
var work1 = new WorkBase("1", someAction);
|
||||||
|
var work2 = new WorkPeriodic("2", (_, _, _) =>
|
||||||
|
{
|
||||||
|
workDone = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}, TimeSpan.FromMilliseconds(1));
|
||||||
|
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
BackgroundWorker.Push(work1);
|
||||||
|
BackgroundWorker.Push(work2);
|
||||||
|
BackgroundWorker.Delete("1");
|
||||||
|
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(10);
|
||||||
|
|
||||||
|
Assert.True(workDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Aborts_long_work()
|
||||||
|
{
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var workCanceled = false;
|
||||||
|
var work = new WorkBase("", async (_, _, token) => await Task.Delay(1000000, token))
|
||||||
|
{
|
||||||
|
Timeout = TimeSpan.FromMilliseconds(1),
|
||||||
|
OnErrorAsync = async (id, ex, token) =>
|
||||||
|
{
|
||||||
|
workCanceled = ex is System.TimeoutException;
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BackgroundWorker.Push(work);
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(20 * 4);
|
||||||
|
|
||||||
|
Assert.True(workCanceled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Execution_continues_after_work_exception()
|
||||||
|
{
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
var work2done = false;
|
||||||
|
var work1 = new WorkBase("1", (_, _, _) => throw new Exception());
|
||||||
|
var work2 = new WorkBase("2", (_, _, _) =>
|
||||||
|
{
|
||||||
|
work2done = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
|
BackgroundWorker.Push(work1);
|
||||||
|
BackgroundWorker.Push(work2);
|
||||||
|
|
||||||
|
await BackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await Task.Delay(2_100);
|
||||||
|
|
||||||
|
Assert.True(work2done);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Push_not_unique_id_should_throw()
|
||||||
|
{
|
||||||
|
var work1 = new WorkPeriodic("1", someAction, TimeSpan.FromSeconds(30));
|
||||||
|
var work2 = new WorkBase("1", someAction);
|
||||||
|
|
||||||
|
var BackgroundWorker = new BackgroundWorker(mockServiceProvider.Object);
|
||||||
|
BackgroundWorker.Push(work1);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentException>(
|
||||||
|
() => BackgroundWorker.Push(work2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
public abstract class CrudServiceTestAbstract<TDto>
|
public abstract class CrudServiceTestAbstract<TDto>
|
||||||
where TDto : AsbCloudApp.Data.IId
|
where TDto : AsbCloudApp.Data.IId
|
||||||
{
|
{
|
||||||
private readonly ICrudService<TDto> service;
|
private readonly ICrudRepository<TDto> service;
|
||||||
|
|
||||||
public CrudServiceTestAbstract()
|
public CrudServiceTestAbstract()
|
||||||
{
|
{
|
||||||
@ -17,7 +17,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
service = MakeService();
|
service = MakeService();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ICrudService<TDto> MakeService();
|
protected abstract ICrudRepository<TDto> MakeService();
|
||||||
protected abstract TDto MakeNewItem();
|
protected abstract TDto MakeNewItem();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -19,10 +19,10 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ICrudService<DepositDto> MakeService()
|
protected override ICrudRepository<DepositDto> MakeService()
|
||||||
{
|
{
|
||||||
var dbContext = TestHelpter.MakeRealTestContext();
|
var dbContext = TestHelpter.MakeRealTestContext();
|
||||||
return new CrudCacheServiceBase<DepositDto, Deposit>(dbContext, TestHelpter.MemoryCache);
|
return new CrudCacheRepositoryBase<DepositDto, Deposit>(dbContext, TestHelpter.MemoryCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
Surname = "Тестович"
|
Surname = "Тестович"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private ICrudService<DrillerDto> service;
|
private ICrudRepository<DrillerDto> service;
|
||||||
|
|
||||||
public DrillerServiceTest()
|
public DrillerServiceTest()
|
||||||
{
|
{
|
||||||
var repositoryMock = RepositoryFactory.Make<ICrudService<DrillerDto>, DrillerDto>(Drillers);
|
var repositoryMock = RepositoryFactory.Make<ICrudRepository<DrillerDto>, DrillerDto>(Drillers);
|
||||||
|
|
||||||
repositoryMock.Setup(x => x.GetAllAsync(It.IsAny<CancellationToken>()))
|
repositoryMock.Setup(x => x.GetAllAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(() => {
|
.Returns(() => {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Background;
|
||||||
using AsbCloudInfrastructure.Services.DrillingProgram;
|
using AsbCloudInfrastructure.Services.DrillingProgram;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -83,8 +83,8 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
private readonly Mock<IUserRepository> userRepositoryMock;
|
private readonly Mock<IUserRepository> userRepositoryMock;
|
||||||
private readonly Mock<IWellService> wellServiceMock;
|
private readonly Mock<IWellService> wellServiceMock;
|
||||||
private readonly Mock<IConfiguration> configurationMock;
|
private readonly Mock<IConfiguration> configurationMock;
|
||||||
private readonly Mock<IBackgroundWorkerService> backgroundWorkerMock;
|
private readonly Mock<BackgroundWorker> backgroundWorkerMock;
|
||||||
private readonly Mock<IEmailService> emailService;
|
private readonly Mock<IEmailService> emailServiceMock;
|
||||||
|
|
||||||
public DrillingProgramServiceTest()
|
public DrillingProgramServiceTest()
|
||||||
{
|
{
|
||||||
@ -102,7 +102,8 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
userRepositoryMock = new Mock<IUserRepository>();
|
userRepositoryMock = new Mock<IUserRepository>();
|
||||||
wellServiceMock = new Mock<IWellService>();
|
wellServiceMock = new Mock<IWellService>();
|
||||||
configurationMock = new Mock<IConfiguration>();
|
configurationMock = new Mock<IConfiguration>();
|
||||||
backgroundWorkerMock = new Mock<IBackgroundWorkerService>();
|
backgroundWorkerMock = new Mock<BackgroundWorker>();
|
||||||
|
emailServiceMock = new Mock<IEmailService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -115,7 +116,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var users = await service.GetAvailableUsers(idWell, CancellationToken.None);
|
var users = await service.GetAvailableUsers(idWell, CancellationToken.None);
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.AddPartsAsync(idWell, new int[] { 1001, 1002 }, CancellationToken.None);
|
var result = await service.AddPartsAsync(idWell, new int[] { 1001, 1002 }, CancellationToken.None);
|
||||||
|
|
||||||
@ -151,7 +152,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.RemovePartsAsync(idWell, new int[] { 1005 }, CancellationToken.None);
|
var result = await service.RemovePartsAsync(idWell, new int[] { 1005 }, CancellationToken.None);
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.AddUserAsync(idWell, 1001, publisher1.Id, 1, CancellationToken.None);
|
var result = await service.AddUserAsync(idWell, 1001, publisher1.Id, 1, CancellationToken.None);
|
||||||
|
|
||||||
@ -209,7 +210,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.RemoveUserAsync(idWell, idFileCategory, publisher1.Id, idUserRole, CancellationToken.None);
|
var result = await service.RemoveUserAsync(idWell, idFileCategory, publisher1.Id, idUserRole, CancellationToken.None);
|
||||||
|
|
||||||
@ -235,7 +236,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var fileMark = new FileMarkDto
|
var fileMark = new FileMarkDto
|
||||||
{
|
{
|
||||||
@ -266,7 +267,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
var fileMark = new FileMarkDto
|
var fileMark = new FileMarkDto
|
||||||
{
|
{
|
||||||
IdFile = file1001.Id,
|
IdFile = file1001.Id,
|
||||||
@ -304,7 +305,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var fileMark = new FileMarkDto
|
var fileMark = new FileMarkDto
|
||||||
{
|
{
|
||||||
@ -331,7 +332,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||||
|
|
||||||
@ -358,12 +359,12 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
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.Enqueue(It.IsAny<Func<string, CancellationToken, Task>>()));
|
backgroundWorkerMock.Verify(s => s.Push(It.IsAny<WorkBase>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -388,7 +389,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailService.Object);
|
emailServiceMock.Object);
|
||||||
|
|
||||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/cluster")]
|
[Route("api/admin/cluster")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminClusterController : CrudController<ClusterDto, ICrudService<ClusterDto>>
|
public class AdminClusterController : CrudController<ClusterDto, ICrudRepository<ClusterDto>>
|
||||||
{
|
{
|
||||||
public AdminClusterController(ICrudService<ClusterDto> service)
|
public AdminClusterController(ICrudRepository<ClusterDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/company")]
|
[Route("api/admin/company")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminCompanyController : CrudController<CompanyDto, ICrudService<CompanyDto>>
|
public class AdminCompanyController : CrudController<CompanyDto, ICrudRepository<CompanyDto>>
|
||||||
{
|
{
|
||||||
public AdminCompanyController(ICrudService<CompanyDto> service)
|
public AdminCompanyController(ICrudRepository<CompanyDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/companyType")]
|
[Route("api/admin/companyType")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminCompanyTypeController : CrudController<CompanyTypeDto, ICrudService<CompanyTypeDto>>
|
public class AdminCompanyTypeController : CrudController<CompanyTypeDto, ICrudRepository<CompanyTypeDto>>
|
||||||
{
|
{
|
||||||
public AdminCompanyTypeController(ICrudService<CompanyTypeDto> service)
|
public AdminCompanyTypeController(ICrudRepository<CompanyTypeDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/deposit")]
|
[Route("api/admin/deposit")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminDepositController : CrudController<DepositDto, ICrudService<DepositDto>>
|
public class AdminDepositController : CrudController<DepositDto, ICrudRepository<DepositDto>>
|
||||||
{
|
{
|
||||||
public AdminDepositController(ICrudService<DepositDto> service)
|
public AdminDepositController(ICrudRepository<DepositDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/permission")]
|
[Route("api/admin/permission")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminPermissionController : CrudController<PermissionDto, ICrudService<PermissionDto>>
|
public class AdminPermissionController : CrudController<PermissionDto, ICrudRepository<PermissionDto>>
|
||||||
{
|
{
|
||||||
public AdminPermissionController(ICrudService<PermissionDto> service)
|
public AdminPermissionController(ICrudRepository<PermissionDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/telemetry")]
|
[Route("api/admin/telemetry")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminTelemetryController : CrudController<TelemetryDto, ICrudService<TelemetryDto>>
|
public class AdminTelemetryController : CrudController<TelemetryDto, ICrudRepository<TelemetryDto>>
|
||||||
{
|
{
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
|
||||||
public AdminTelemetryController(ICrudService<TelemetryDto> service,
|
public AdminTelemetryController(ICrudRepository<TelemetryDto> service,
|
||||||
ITelemetryService telemetryService)
|
ITelemetryService telemetryService)
|
||||||
: base(service)
|
: base(service)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/user")]
|
[Route("api/admin/user")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminUserController : CrudController<UserExtendedDto, ICrudService<UserExtendedDto>>
|
public class AdminUserController : CrudController<UserExtendedDto, ICrudRepository<UserExtendedDto>>
|
||||||
{
|
{
|
||||||
public AdminUserController(IUserRepository service)
|
public AdminUserController(IUserRepository service)
|
||||||
: base(service)
|
: base(service)
|
||||||
|
@ -13,7 +13,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/admin/well")]
|
[Route("api/admin/well")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminWellController : CrudController<WellDto, ICrudService<WellDto>>
|
public class AdminWellController : CrudController<WellDto, ICrudRepository<WellDto>>
|
||||||
{
|
{
|
||||||
public AdminWellController(IWellService service)
|
public AdminWellController(IWellService service)
|
||||||
: base(service)
|
: base(service)
|
||||||
|
@ -21,7 +21,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public abstract class CrudController<T, TService> : ControllerBase
|
public abstract class CrudController<T, TService> : ControllerBase
|
||||||
where T : IId
|
where T : IId
|
||||||
where TService : ICrudService<T>
|
where TService : ICrudRepository<T>
|
||||||
{
|
{
|
||||||
protected readonly TService service;
|
protected readonly TService service;
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await service.UpdateAsync(value, token).ConfigureAwait(false);
|
var result = await service.UpdateAsync(value, token).ConfigureAwait(false);
|
||||||
if (result == ICrudService<T>.ErrorIdNotFound)
|
if (result == ICrudRepository<T>.ErrorIdNotFound)
|
||||||
return BadRequest($"id:{value.Id} does not exist in the db");
|
return BadRequest($"id:{value.Id} does not exist in the db");
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await service.DeleteAsync(id, token).ConfigureAwait(false);
|
var result = await service.DeleteAsync(id, token).ConfigureAwait(false);
|
||||||
if (result == ICrudService<T>.ErrorIdNotFound)
|
if (result == ICrudRepository<T>.ErrorIdNotFound)
|
||||||
return NoContent();
|
return NoContent();
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/driller")]
|
[Route("api/driller")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class DrillerController : CrudController<DrillerDto, ICrudService<DrillerDto>>
|
public class DrillerController : CrudController<DrillerDto, ICrudRepository<DrillerDto>>
|
||||||
{
|
{
|
||||||
public DrillerController(ICrudService<DrillerDto> service)
|
public DrillerController(ICrudRepository<DrillerDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("api/[Controller]")]
|
[Route("api/[Controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class FileCategoryController : CrudController<FileCategoryDto, ICrudService<FileCategoryDto>>
|
public class FileCategoryController : CrudController<FileCategoryDto, ICrudRepository<FileCategoryDto>>
|
||||||
{
|
{
|
||||||
public FileCategoryController(ICrudService<FileCategoryDto> service, IFileCategoryService fileCategoryService)
|
public FileCategoryController(ICrudRepository<FileCategoryDto> service, IFileCategoryService fileCategoryService)
|
||||||
: base(service)
|
: base(service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,18 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
return Ok(subsystemResult);
|
return Ok(subsystemResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение словаря названий ограничений
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("names")]
|
||||||
|
[ProducesResponseType(typeof(Dictionary<int, string>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public IActionResult GetLimitingParameteraNames()
|
||||||
|
{
|
||||||
|
var feedRegulatorData = limitingParameterService.GetLimitingParameteraNames();
|
||||||
|
return Ok(feedRegulatorData);
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<bool> UserHasAccesToWellAsync(int idWell, CancellationToken token)
|
protected async Task<bool> UserHasAccesToWellAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var idCompany = User.GetCompanyId();
|
var idCompany = User.GetCompanyId();
|
||||||
|
@ -68,7 +68,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
}, token);
|
}, token);
|
||||||
|
|
||||||
var id = reportService.CreateReport(idWell, (int)idUser,
|
var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser,
|
||||||
stepSeconds, format, begin, end, HandleReportProgressAsync);
|
stepSeconds, format, begin, end, HandleReportProgressAsync);
|
||||||
|
|
||||||
return Ok(id);
|
return Ok(id);
|
||||||
|
@ -12,9 +12,9 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
|||||||
[Route("api/admin/subsystem")]
|
[Route("api/admin/subsystem")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class AdminSubsystemController : CrudController<SubsystemDto, ICrudService<SubsystemDto>>
|
public class AdminSubsystemController : CrudController<SubsystemDto, ICrudRepository<SubsystemDto>>
|
||||||
{
|
{
|
||||||
public AdminSubsystemController(ICrudService<SubsystemDto> service)
|
public AdminSubsystemController(ICrudRepository<SubsystemDto> service)
|
||||||
: base(service)
|
: base(service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ using AsbCloudApp.Requests;
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudApp.Services.Subsystems;
|
using AsbCloudApp.Services.Subsystems;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -25,6 +24,14 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
|||||||
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly ISubsystemService subsystemService;
|
private readonly ISubsystemService subsystemService;
|
||||||
|
|
||||||
|
private readonly Dictionary<int, string> subsystemNames = new()
|
||||||
|
{
|
||||||
|
{ 1, "SAUB" },
|
||||||
|
{ 65537, "Torque Master" },
|
||||||
|
{ 65536, "Spin Master" }
|
||||||
|
};
|
||||||
|
|
||||||
public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService, ISubsystemService subsystemService)
|
public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService, ISubsystemService subsystemService)
|
||||||
{
|
{
|
||||||
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
||||||
@ -131,6 +138,17 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение словаря названий подсистем
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("names")]
|
||||||
|
[ProducesResponseType(typeof(Dictionary<int, string>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public IActionResult GetSubsystemsNames()
|
||||||
|
{
|
||||||
|
return Ok(subsystemNames);
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<bool> UserHasAccesToWellAsync(int idWell, CancellationToken token)
|
protected async Task<bool> UserHasAccesToWellAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var idCompany = User.GetCompanyId();
|
var idCompany = User.GetCompanyId();
|
||||||
|
@ -43,6 +43,7 @@ namespace AsbCloudWebApi.Middlewares
|
|||||||
sw.Stop();
|
sw.Stop();
|
||||||
requestLog.ElapsedMilliseconds = sw.ElapsedMilliseconds;
|
requestLog.ElapsedMilliseconds = sw.ElapsedMilliseconds;
|
||||||
requestLog.Status = context.Response.StatusCode;
|
requestLog.Status = context.Response.StatusCode;
|
||||||
|
// TODO: Add request params and body size.
|
||||||
service.RegisterRequestError(requestLog, ex);
|
service.RegisterRequestError(requestLog, ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace AsbCloudWebApi.Middlewares
|
|||||||
{
|
{
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex) // TODO: find explicit exception. Use Trace. Add body size to message.
|
||||||
{
|
{
|
||||||
if (ex.Message.Contains("Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate."))
|
if (ex.Message.Contains("Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate."))
|
||||||
Console.WriteLine("Reading the request body timed out due to data arriving too slowly.");
|
Console.WriteLine("Reading the request body timed out due to data arriving too slowly.");
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
using DocumentFormat.OpenXml.InkML;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace AsbCloudWebApi
|
namespace AsbCloudWebApi
|
||||||
{
|
{
|
||||||
@ -15,30 +10,8 @@ namespace AsbCloudWebApi
|
|||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
IConfigurationRoot configuration = new ConfigurationBuilder()
|
|
||||||
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
|
|
||||||
.AddJsonFile("appsettings.json")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
if (args?.Length > 0)
|
|
||||||
{
|
|
||||||
if (args.Contains("db_init"))
|
|
||||||
{
|
|
||||||
var connectionStringName = "DefaultConnection";
|
|
||||||
|
|
||||||
var context = AsbCloudInfrastructure.DependencyInjection.MakeContext(configuration.GetConnectionString(connectionStringName));
|
|
||||||
context.Database.SetCommandTimeout(TimeSpan.FromSeconds(5 * 60));
|
|
||||||
context.Database.Migrate();
|
|
||||||
|
|
||||||
Console.WriteLine("Óñïåøíî âûïîëíåíî.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WriteHelp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var host = CreateHostBuilder(args).Build();
|
var host = CreateHostBuilder(args).Build();
|
||||||
AsbCloudInfrastructure.Startup.BeforeRunHandler(host, configuration);
|
AsbCloudInfrastructure.Startup.BeforeRunHandler(host);
|
||||||
host.Run();
|
host.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,17 +21,5 @@ namespace AsbCloudWebApi
|
|||||||
{
|
{
|
||||||
webBuilder.UseStartup<Startup>();
|
webBuilder.UseStartup<Startup>();
|
||||||
});
|
});
|
||||||
|
|
||||||
private static void WriteHelp()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Ïðè çàïóñêå áåç êëþ÷åé ïðîãðàììà ïðîñòî ñòàðòóåò â îáû÷íîì ðåæèìå.");
|
|
||||||
Console.WriteLine("Êëþ÷è äëÿ çàïóñêà:");
|
|
||||||
Console.WriteLine("db_init - ñîçäàòü êîíòåêñò ÁÄ è âûéòè.");
|
|
||||||
Console.WriteLine("Êîíòåêñò ñîçäàñòñÿ äëÿ ñòðîêè ïîäêëþ÷åíèÿ \"DefaultConnection\"");
|
|
||||||
Console.WriteLine("Ñîçäàíèå êîíòåêñòà ïðèâåäåò ê ñîçäàíèþ ÁÄ, åñëè åé íåò");
|
|
||||||
Console.WriteLine("è ïðèìåíåíèþ âñåõ ìèãðàöèé, åñëè ÁÄ óæå åñòü.");
|
|
||||||
Console.WriteLine("Äëÿ ñîçäàíèÿ êîíòåêñòà â ÁÄ äîëæíà áûòü ñîçäàíà ñõåìà public");
|
|
||||||
Console.WriteLine("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user