Извлечен интерфейс из TelemetryDataCache<TDto>для тестов.

This commit is contained in:
ngfrolov 2023-10-24 09:23:07 +05:00
parent b8462253b3
commit bf9895667d
Signed by untrusted user who does not match committer: ng.frolov
GPG Key ID: E99907A0357B29A7
11 changed files with 108 additions and 37 deletions

View File

@ -0,0 +1,62 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using System;
using System.Collections.Generic;
namespace AsbCloudApp.Repositories
{
/// <summary>
/// Хранилище кеша
/// </summary>
/// <typeparam name="TDto"></typeparam>
public interface ITelemetryDataCache<TDto> where TDto : ITelemetryData
{
/// <summary>
/// добавить в кеш чанк записей по телеметрии
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="range"></param>
void AddRange(int idTelemetry, IEnumerable<TDto> range);
/// <summary>
/// вернуть последнюю записть
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
TDto? GetLastOrDefault(int idTelemetry);
/// <summary>
/// Получить кешированые записи
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="dateBegin"></param>
/// <param name="intervalSec"></param>
/// <param name="approxPointsCount">приблизительное кол-во возвращаемых записей после их прореживания</param>
/// <returns></returns>
IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600, int approxPointsCount = 1024);
/// <summary>
/// Получить кешированые записи
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="request"></param>
/// <returns></returns>
IEnumerable<TDto>? GetOrDefault(int idTelemetry, TelemetryDataRequest request);
/// <summary>
/// Получить диапазон дат телеметрии.
/// Дата первой записи телеметрии храниться отдельно и запоняется при инициализации
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry);
/// <summary>
/// Получение первой и последней записи телеметрии.
/// Первая запись телеметрии храниться отдельно и запоняется при инициализации
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
(TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry);
}
}

View File

@ -159,8 +159,8 @@ namespace AsbCloudInfrastructure
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>()); services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>());
services.AddSingleton(new WitsInfoService()); services.AddSingleton(new WitsInfoService());
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider)); services.AddSingleton<ITelemetryDataCache<TelemetryDataSaubDto>>(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider)); services.AddSingleton<ITelemetryDataCache<TelemetryDataSpinDto>>(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>(); services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
services.AddSingleton<BackgroundWorker>(); services.AddSingleton<BackgroundWorker>();
services.AddSingleton<NotificationBackgroundWorker>(); services.AddSingleton<NotificationBackgroundWorker>();

View File

@ -1,4 +1,5 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb; using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
@ -18,12 +19,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
protected readonly IAsbCloudDbContext db; protected readonly IAsbCloudDbContext db;
protected readonly ITelemetryService telemetryService; protected readonly ITelemetryService telemetryService;
protected readonly TelemetryDataCache<TDto> telemetryDataCache; protected readonly ITelemetryDataCache<TDto> telemetryDataCache;
public TelemetryDataBaseService( public TelemetryDataBaseService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
TelemetryDataCache<TDto> telemetryDataCache) ITelemetryDataCache<TDto> telemetryDataCache)
{ {
this.db = db; this.db = db;
this.telemetryService = telemetryService; this.telemetryService = telemetryService;

View File

@ -12,11 +12,11 @@ using AsbCloudInfrastructure.Background;
using System.Threading; using System.Threading;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Repositories;
namespace AsbCloudInfrastructure.Services.SAUB namespace AsbCloudInfrastructure.Services.SAUB
{ {
public class TelemetryDataCache<TDto> public class TelemetryDataCache<TDto> : ITelemetryDataCache<TDto> where TDto : AsbCloudApp.Data.ITelemetryData
where TDto : AsbCloudApp.Data.ITelemetryData
{ {
class TelemetryDataCacheItem class TelemetryDataCacheItem
{ {
@ -48,7 +48,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
instance = new TelemetryDataCache<TDto>(); instance = new TelemetryDataCache<TDto>();
var worker = provider.GetRequiredService<BackgroundWorker>(); var worker = provider.GetRequiredService<BackgroundWorker>();
var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}";
var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => { var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) =>
{
var db = provider.GetRequiredService<IAsbCloudDbContext>(); var db = provider.GetRequiredService<IAsbCloudDbContext>();
await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token); await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token);
}); });
@ -85,13 +86,13 @@ namespace AsbCloudInfrastructure.Services.SAUB
} }
else else
{ {
cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem()
{ {
FirstByDate = newItems.ElementAt(0), FirstByDate = newItems.ElementAt(0),
LastData = new CyclycArray<TDto>(activeWellCapacity) LastData = new CyclycArray<TDto>(activeWellCapacity)
}); });
} }
cacheItem.LastData.AddRange(newItems); cacheItem.LastData.AddRange(newItems);
} }
@ -107,14 +108,14 @@ namespace AsbCloudInfrastructure.Services.SAUB
/// <returns></returns> /// <returns></returns>
public IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) public IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024)
{ {
if(!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return null; return null;
var cacheLastData = cacheItem.LastData; var cacheLastData = cacheItem.LastData;
if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin) if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin)
return null; return null;
var dateEnd = dateBegin.AddSeconds(intervalSec); var dateEnd = dateBegin.AddSeconds(intervalSec);
var items = cacheLastData var items = cacheLastData
.Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd);
@ -141,7 +142,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
return null; return null;
var from = cacheItem.FirstByDate?.DateTime; var from = cacheItem.FirstByDate?.DateTime;
if(!cacheItem.LastData.Any()) if (!cacheItem.LastData.Any())
return null; return null;
var to = cacheItem.LastData[^1].DateTime; var to = cacheItem.LastData[^1].DateTime;
@ -190,10 +191,10 @@ namespace AsbCloudInfrastructure.Services.SAUB
var idTelemetry = well.IdTelemetry!.Value; var idTelemetry = well.IdTelemetry!.Value;
var hoursOffset = well.Timezone.Hours; var hoursOffset = well.Timezone.Hours;
onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count); onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count);
var cacheItem = await GetOrDefaultCacheDataFromDbAsync<TEntity>(db, idTelemetry, capacity, hoursOffset, token); var cacheItem = await GetOrDefaultCacheDataFromDbAsync<TEntity>(db, idTelemetry, capacity, hoursOffset, token);
if(cacheItem is not null) if (cacheItem is not null)
caches.TryAdd(idTelemetry, cacheItem); caches.TryAdd(idTelemetry, cacheItem);
} }
@ -225,7 +226,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
var dtos = entities var dtos = entities
.AsEnumerable() .AsEnumerable()
.Reverse() .Reverse()
.Select(entity => { .Select(entity =>
{
var dto = entity.Adapt<TDto>(); var dto = entity.Adapt<TDto>();
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
return dto; return dto;
@ -247,12 +249,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return null; return null;
IEnumerable<TDto> data = cacheItem.LastData; IEnumerable<TDto> data = cacheItem.LastData;
if (!data.Any()) if (!data.Any())
return null; return null;
if (request.GeDate.HasValue) if (request.GeDate.HasValue)
{ {
var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours);
@ -272,7 +274,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours);
data = data.Where(d => d.DateTime >= request.LeDate); data = data.Where(d => d.DateTime >= request.LeDate);
} }
if (request.Divider > 1) if (request.Divider > 1)
data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0);

View File

@ -1,6 +1,7 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
@ -26,7 +27,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
ITelemetryUserService telemetryUserService, ITelemetryUserService telemetryUserService,
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache) ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
: base(db, telemetryService, telemetryDataCache) : base(db, telemetryService, telemetryDataCache)
{ {
this.telemetryUserService = telemetryUserService; this.telemetryUserService = telemetryUserService;

View File

@ -1,4 +1,5 @@
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
@ -11,7 +12,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryDataSpinService( public TelemetryDataSpinService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache) ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache)
: base(db, telemetryService, telemetryDataCache) : base(db, telemetryService, telemetryDataCache)
{ } { }

View File

@ -1,5 +1,6 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb; using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
@ -18,7 +19,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
private readonly TelemetryDataCache<TelemetryDataSaubDto> dataSaubCache; //TODO: методы использующие ITelemetryDataCache, скорее всего, тут не нужны
private readonly ITelemetryDataCache<TelemetryDataSaubDto> dataSaubCache;
private readonly ITimezoneService timezoneService; private readonly ITimezoneService timezoneService;
public ITimezoneService TimeZoneService => timezoneService; public ITimezoneService TimeZoneService => timezoneService;
@ -26,7 +28,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryService( public TelemetryService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
IMemoryCache memoryCache, IMemoryCache memoryCache,
TelemetryDataCache<TelemetryDataSaubDto> dataSaubCache, ITelemetryDataCache<TelemetryDataSaubDto> dataSaubCache,
ITimezoneService timezoneService) ITimezoneService timezoneService)
{ {
this.db = db; this.db = db;

View File

@ -36,7 +36,7 @@ public class WellInfoService
var operationsStatService = services.GetRequiredService<IOperationsStatService>(); var operationsStatService = services.GetRequiredService<IOperationsStatService>();
var processMapPlanWellDrillingRepository = services.GetRequiredService<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>(); var processMapPlanWellDrillingRepository = services.GetRequiredService<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>();
var subsystemOperationTimeService = services.GetRequiredService<ISubsystemOperationTimeService>(); var subsystemOperationTimeService = services.GetRequiredService<ISubsystemOperationTimeService>();
var telemetryDataSaubCache = services.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>(); var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>(); var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
var wells = await wellService.GetAllAsync(token); var wells = await wellService.GetAllAsync(token);
@ -180,16 +180,16 @@ public class WellInfoService
public IEnumerable<int> IdsCompanies { get; set; } = null!; public IEnumerable<int> IdsCompanies { get; set; } = null!;
} }
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache; private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache;
private readonly TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache; private readonly ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache;
private readonly IWitsRecordRepository<Record7Dto> witsRecord7Repository; private readonly IWitsRecordRepository<Record7Dto> witsRecord7Repository;
private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository; private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository;
private readonly IGtrRepository gtrRepository; private readonly IGtrRepository gtrRepository;
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>(); private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
public WellInfoService( public WellInfoService(
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache, ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache,
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache, ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache,
IWitsRecordRepository<Record7Dto> witsRecord7Repository, IWitsRecordRepository<Record7Dto> witsRecord7Repository,
IWitsRecordRepository<Record1Dto> witsRecord1Repository, IWitsRecordRepository<Record1Dto> witsRecord1Repository,
IGtrRepository gtrRepository) IGtrRepository gtrRepository)

View File

@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using AsbCloudInfrastructure.Services.SAUB; using AsbCloudInfrastructure.Services.SAUB;
using AsbCloudApp.Repositories;
namespace AsbCloudInfrastructure.Services.WellOperationService; namespace AsbCloudInfrastructure.Services.WellOperationService;
@ -19,10 +20,10 @@ public class OperationsStatService : IOperationsStatService
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache; private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService,
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache) ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
{ {
this.db = db; this.db = db;
this.memoryCache = memoryCache; this.memoryCache = memoryCache;

View File

@ -16,12 +16,12 @@ public class WellboreService : IWellboreService
const string WellboreNameFormat = "Ñòâîë {0}"; const string WellboreNameFormat = "Ñòâîë {0}";
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationRepository wellOperationRepository;
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache; private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
public WellboreService( public WellboreService(
IWellService wellService, IWellService wellService,
IWellOperationRepository wellOperationRepository, IWellOperationRepository wellOperationRepository,
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache) ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
{ {
this.wellService = wellService; this.wellService = wellService;
this.wellOperationRepository = wellOperationRepository; this.wellOperationRepository = wellOperationRepository;

View File

@ -15,6 +15,7 @@ using AsbCloudInfrastructure.Services.Subsystems;
using System.Linq; using System.Linq;
using DocumentFormat.OpenXml.InkML; using DocumentFormat.OpenXml.InkML;
using AsbCloudDb; using AsbCloudDb;
using AsbCloudApp.Repositories;
namespace AsbCloudInfrastructure namespace AsbCloudInfrastructure
{ {
@ -29,8 +30,8 @@ namespace AsbCloudInfrastructure
context.Database.EnshureCreatedAndMigrated(); context.Database.EnshureCreatedAndMigrated();
// TODO: Сделать инициализацию кеша телеметрии более явной. // TODO: Сделать инициализацию кеша телеметрии более явной.
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>(); _ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSpinDto>>(); _ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSpinDto>>();
var backgroundWorker = provider.GetRequiredService<BackgroundWorker>(); var backgroundWorker = provider.GetRequiredService<BackgroundWorker>();
backgroundWorker.WorkStore.AddPeriodic<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30)); backgroundWorker.WorkStore.AddPeriodic<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));