Merge branch 'dev' into fix/save-fact-operations

This commit is contained in:
on.nemtina 2023-05-22 14:48:10 +05:00
commit c993feb182
14 changed files with 174 additions and 375 deletions

View File

@ -16,11 +16,6 @@ namespace AsbCloudApp.Services
/// </summary>
ITimezoneService TimeZoneService { get; }
/// <summary>
/// трекер запросов
/// </summary>
ITelemetryTracker TelemetryTracker { get; }
/// <summary>
/// получить idWell по uid телеметрии
/// </summary>
@ -42,13 +37,6 @@ namespace AsbCloudApp.Services
/// <returns></returns>
SimpleTimezoneDto GetTimezone(int idTelemetry);
/// <summary>
/// Получить дату получения последних данных
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
DateTime GetLastTelemetryDate(int idTelemetry);
/// <summary>
/// получить idTelemetry по IdWell
/// </summary>

View File

@ -1,39 +0,0 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
namespace AsbCloudApp.Services
{
/// <summary>
/// Сервис статистики телеметрии
/// </summary>
public interface ITelemetryTracker
{
/// <summary>
/// получить дату последней отправки данных панелью
/// </summary>
/// <param name="uid"></param>
/// <returns></returns>
DateTimeOffset GetLastTelemetryDateByUid(string uid);
/// <summary>
/// получить диапазон дат за которые есть данные по телеметрии
/// </summary>
/// <param name="uid"></param>
/// <returns></returns>
DatesRangeDto GetTelemetryDateRangeByUid(string uid);
/// <summary>
/// список передающих телеметрий
/// </summary>
/// <returns></returns>
IEnumerable<string> GetTransmittingTelemetriesUids();
/// <summary>
/// обновить статистику по телеметрии
/// </summary>
/// <param name="uid"></param>
/// <param name="remoteDate"></param>
void SaveRequestDate(string uid, DateTimeOffset remoteDate);
}
}

View File

@ -63,7 +63,7 @@ namespace AsbCloudApp.Services
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
DateTimeOffset GetLastTelemetryDate(int idWell);
DateTime GetLastTelemetryDate(int idWell);
//TODO: выяснить и удалить отсюда
/// <summary>

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Concurrent;
namespace AsbCloudApp.Services
{
/// <summary>
/// Репозиторий для хранения в оперативке данных (от панели)
/// </summary>
public class InstantDataRepository : ConcurrentDictionary<int, ConcurrentDictionary<Type, object>>
{
}
}

View File

@ -1,12 +1,10 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.GTR;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
using AsbCloudDb.Model.GTR;
using AsbCloudDb.Model.Subsystems;
using AsbCloudInfrastructure.Background;
using AsbCloudInfrastructure.Repository;
@ -102,10 +100,8 @@ namespace AsbCloudInfrastructure
services.AddScoped<IEmailService, EmailService>();
services.AddSingleton(new WitsInfoService());
services.AddSingleton(new InstantDataRepository());
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(configuration));
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
services.AddSingleton<ITelemetryTracker, TelemetryTracker>();
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
services.AddSingleton<BackgroundWorker>();
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));

View File

@ -111,7 +111,7 @@ namespace AsbCloudInfrastructure.Repository
{
var dto = well.Adapt<WellDto>();
dto.WellType = well.WellType.Caption;
dto.LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id).DateTime;
dto.LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id);
dto.Cluster = gCluster.Key.Caption;
dto.Deposit = gDeposit.Key.Caption;
return dto;

View File

@ -64,7 +64,6 @@ namespace AsbCloudInfrastructure.Services.SAUB
});
var entityMaxDate = entities.Max(e => e.DateTime);
telemetryService.TelemetryTracker.SaveRequestDate(uid, entityMaxDate);
var dbset = db.Set<TEntity>();
var stopwatch = Stopwatch.StartNew();
@ -101,19 +100,15 @@ namespace AsbCloudInfrastructure.Services.SAUB
DateTimeOffset dateBeginUtc;
if (dateBegin == default)
{
dateBeginUtc = telemetryService.GetLastTelemetryDate(telemetry.Id)
.ToUtcDateTimeOffset(timezone.Hours);
if (dateBeginUtc != default)
dateBeginUtc = dateBeginUtc.AddSeconds(-intervalSec);
var dateRange = telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id);
dateBeginUtc = (dateRange?.To.ToUtcDateTimeOffset(timezone.Hours) ?? DateTime.UtcNow)
.AddSeconds(-intervalSec);
}
else
{
dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours);
}
if (dateBeginUtc == default)
dateBeginUtc = DateTime.UtcNow.AddSeconds(-intervalSec);
var cacheData = telemetryDataCache.GetOrDefault(telemetry.Id, dateBeginUtc.ToRemoteDateTime(timezone.Hours), intervalSec, approxPointsCount);
if (cacheData is not null)
return cacheData;

View File

@ -7,17 +7,28 @@ using Microsoft.EntityFrameworkCore;
using Mapster;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AsbCloudInfrastructure.Background;
using System.Threading;
using AsbCloudApp.Data;
namespace AsbCloudInfrastructure.Services.SAUB
{
public class TelemetryDataCache<TDto>
where TDto : AsbCloudApp.Data.ITelemetryData
{
class TelemetryDataCacheItem
{
public TDto? FirstByDate { get; init; }
public CyclycArray<TDto> LastData { get; init; } = null!;
}
private IServiceProvider provider = null!;
private const int activeWellCapacity = 12 * 60 * 60;
private const int doneWellCapacity = 65 * 60;
private readonly ConcurrentDictionary<int, CyclycArray<TDto>> caches;
// key == idTelemetry
private readonly ConcurrentDictionary<int, TelemetryDataCacheItem> caches;
private bool isLoading = false;
private TelemetryDataCache()
@ -27,35 +38,22 @@ namespace AsbCloudInfrastructure.Services.SAUB
private static TelemetryDataCache<TDto>? instance;
//TODO: Move initialize fromDB to bacground service task
public static TelemetryDataCache<TDto> GetInstance<TEntity>(IConfiguration configuration)
where TEntity : class, ITelemetryData
public static TelemetryDataCache<TDto> GetInstance<TEntity>(IServiceProvider provider)
where TEntity : class, AsbCloudDb.Model.ITelemetryData
{
if (instance is null)
{
instance = new TelemetryDataCache<TDto>();
_ = Task.Run(() =>
{
using var db = MakeContext(configuration);
instance.InitializeCacheFromDB<TEntity>(db);
db.Dispose();
var worker = provider.GetRequiredService<BackgroundWorker>();
var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}";
var work = new WorkBase(workId, async (workId, provider, token) => {
var db = provider.GetRequiredService<IAsbCloudDbContext>();
await instance.InitializeCacheFromDBAsync<TEntity>(db, token);
});
worker.Push(work);
}
return instance;
}
public static TelemetryDataCache<TDto> GetInstance<TEntity>(IAsbCloudDbContext db, out Task initializationTask)
where TEntity : class, ITelemetryData
{
if (instance is null)
{
instance = new TelemetryDataCache<TDto>();
initializationTask = Task.Run(() =>
{
instance.InitializeCacheFromDB<TEntity>(db);
});
}
else
initializationTask = Task.CompletedTask;
instance.provider = provider;
return instance;
}
@ -66,24 +64,33 @@ namespace AsbCloudInfrastructure.Services.SAUB
/// <param name="range"></param>
public void AddRange(int idTelemetry, IEnumerable<TDto> range)
{
CyclycArray<TDto> cacheItem;
if (!range.Any())
return;
var newItems = range
.OrderBy(i => i.DateTime);
foreach (var item in newItems)
item.IdTelemetry = idTelemetry;
TelemetryDataCacheItem cacheItem;
if (isLoading)
{
if (caches.TryGetValue(idTelemetry, out CyclycArray<TDto>? localCacheItem))
if (caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? localCacheItem))
cacheItem = localCacheItem;
else
return;
}
else
{
cacheItem = caches.GetOrAdd(idTelemetry, _ => new CyclycArray<TDto>(activeWellCapacity));
cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem()
{
FirstByDate = newItems.ElementAt(0),
LastData = new CyclycArray<TDto>(activeWellCapacity)
});
}
var newItems = range
.OrderBy(i => i.DateTime);
foreach (var item in newItems)
item.IdTelemetry = idTelemetry;
cacheItem.AddRange(newItems);
cacheItem.LastData.AddRange(newItems);
}
/// <summary>
@ -98,14 +105,16 @@ namespace AsbCloudInfrastructure.Services.SAUB
/// <returns></returns>
public IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024)
{
if(!caches.TryGetValue(idTelemetry, out CyclycArray<TDto>? cacheItem))
if(!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return null;
if (cacheItem is null || !cacheItem.Any() || cacheItem[0].DateTime > dateBegin)
var cacheLastData = cacheItem.LastData;
if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin)
return null;
var dateEnd = dateBegin.AddSeconds(intervalSec);
var items = cacheItem
var items = cacheLastData
.Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd);
var ratio = items.Count() / approxPointsCount;
@ -116,19 +125,43 @@ namespace AsbCloudInfrastructure.Services.SAUB
return items;
}
private void InitializeCacheFromDB<TEntity>(IAsbCloudDbContext db)
where TEntity : class, ITelemetryData
public TDto? GetLastOrDefault(int idTelemetry)
{
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return default;
return cacheItem.LastData.LastOrDefault();
}
public DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry)
{
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return null;
var from = cacheItem.FirstByDate?.DateTime;
if(!cacheItem.LastData.Any())
return null;
var to = cacheItem.LastData[^1].DateTime;
from = from ?? cacheItem.LastData[0].DateTime;
return new DatesRangeDto { From = from.Value, To = to };
}
private async Task InitializeCacheFromDBAsync<TEntity>(IAsbCloudDbContext db, CancellationToken token)
where TEntity : class, AsbCloudDb.Model.ITelemetryData
{
if (isLoading)
throw new Exception("Multiple cache loading detected.");
isLoading = true;
Well[] wells = Array.Empty<Well>();
wells = db.Set<Well>()
.Include(well => well.Telemetry)
.Include(well => well.Cluster)
.Where(well => well.IdTelemetry != null)
.ToArray();
wells = await db.Set<Well>()
.Include(well => well.Telemetry)
.Include(well => well.Cluster)
.Where(well => well.IdTelemetry != null)
.ToArrayAsync(token);
foreach (Well well in wells)
{
@ -139,46 +172,61 @@ namespace AsbCloudInfrastructure.Services.SAUB
var idTelemetry = well.IdTelemetry!.Value;
var hoursOffset = well.Timezone.Hours;
IEnumerable<TDto> cacheItemData = GetCacheDataFromDb<TEntity>(db, idTelemetry, capacity, hoursOffset);
var cacheItem = new CyclycArray<TDto>(capacity);
cacheItem.AddRange(cacheItemData);
caches.TryAdd(idTelemetry, cacheItem);
System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}> for well: {well.Cluster?.Caption}/{well.Caption} loaded");
var cacheItem = await GetOrDefaultCacheDataFromDbAsync<TEntity>(db, idTelemetry, capacity, hoursOffset, token);
if(cacheItem is not null)
{
caches.TryAdd(idTelemetry, cacheItem);
System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}> for well: {well.Cluster?.Caption}/{well.Caption} loaded");
}
else
{
System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}> for well: {well.Cluster?.Caption}/{well.Caption} has no data");
}
}
System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}> load complete");
isLoading = false;
}
private static IAsbCloudDbContext MakeContext(IConfiguration configuration)
private static async Task<TelemetryDataCacheItem?> GetOrDefaultCacheDataFromDbAsync<TEntity>(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token)
where TEntity : class, AsbCloudDb.Model.ITelemetryData
{
var connectionString = configuration.GetConnectionString("DefaultConnection");
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql(connectionString)
.Options;
var db = new AsbCloudDbContext(options);
return db;
}
var query = db.Set<TEntity>()
.Where(i => i.IdTelemetry == idTelemetry);
private static IEnumerable<TDto> GetCacheDataFromDb<TEntity>(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset)
where TEntity : class, ITelemetryData
{
var entities = db.Set<TEntity>()
.Where(i => i.IdTelemetry == idTelemetry)
var firstDbEntity = await query
.OrderBy(i => i.DateTime)
.FirstOrDefaultAsync(token);
if (firstDbEntity is null)
return default;
var first = firstDbEntity.Adapt<TDto>();
first.DateTime = firstDbEntity.DateTime.ToRemoteDateTime(hoursOffset);
var entities = await query
.OrderByDescending(i => i.DateTime)
.Take(capacity)
.ToArray()
.ToArrayAsync(token);
var dtos = entities
.AsEnumerable()
.Reverse();
.Reverse()
.Select(entity => {
var dto = entity.Adapt<TDto>();
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
return dto;
});
var dtos = entities.Select(entity => {
var dto = entity.Adapt<TDto>();
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
return dto;
});
var cacheItem = new CyclycArray<TDto>(capacity);
cacheItem.AddRange(dtos);
return dtos;
var item = new TelemetryDataCacheItem
{
FirstByDate = first,
LastData = cacheItem,
};
return item;
}
}
}

View File

@ -19,21 +19,20 @@ namespace AsbCloudInfrastructure.Services.SAUB
{
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
private readonly ITelemetryTracker telemetryTracker;
private readonly TelemetryDataCache<TelemetryDataSaubDto> dataSaubCache;
private readonly ITimezoneService timezoneService;
public ITimezoneService TimeZoneService => timezoneService;
public ITelemetryTracker TelemetryTracker => telemetryTracker;
public TelemetryService(
IAsbCloudDbContext db,
IMemoryCache memoryCache,
ITelemetryTracker telemetryTracker,
TelemetryDataCache<TelemetryDataSaubDto> dataSaubCache,
ITimezoneService timezoneService)
{
this.db = db;
this.memoryCache = memoryCache;
this.telemetryTracker = telemetryTracker;
this.dataSaubCache = dataSaubCache;
this.timezoneService = timezoneService;
}
@ -47,34 +46,11 @@ namespace AsbCloudInfrastructure.Services.SAUB
memoryCache.DropBasic<Telemetry>();
}
public DateTime GetLastTelemetryDate(int idTelemetry)
{
var telemetry = GetTelemetryCache().FirstOrDefault(t => t.Id == idTelemetry);
if (telemetry is null)
throw new Exception($"Telemetry id:{idTelemetry} does not exist");
var uid = telemetry.RemoteUid;
var timzone = GetTimezone(idTelemetry);
var lastTelemetryDate = telemetryTracker.GetLastTelemetryDateByUid(uid);
return lastTelemetryDate.ToRemoteDateTime(timzone.Hours);
}
public DatesRangeDto GetDatesRange(int idTelemetry)
{
var telemetry = GetTelemetryCache().FirstOrDefault(t => t.Id == idTelemetry);
if (telemetry is null)
throw new Exception($"Telemetry id:{idTelemetry} does not exist");
var dto = TelemetryTracker.GetTelemetryDateRangeByUid(telemetry.RemoteUid);
if (dto is null)
throw new Exception($"Telemetry id:{idTelemetry} has no data");
var timezone = GetTimezone(idTelemetry);
dto.From = dto.From.ToTimeZoneOffsetHours(timezone.Hours);
dto.To = dto.To.ToTimeZoneOffsetHours(timezone.Hours);
return dto;
var cacheDataRange = dataSaubCache.GetOrDefaultDataDateRange(idTelemetry)
?? new ();
return cacheDataRange;
}
public int GetOrCreateTelemetryIdByUid(string uid)

View File

@ -1,156 +0,0 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.SAUB
{
public class TelemetryTracker : ITelemetryTracker
{
class TrackerStat
{
//public int Id { get; set; }
public string RemoteUid { get; set; } = null!;
/// <summary>
/// Время последнего запроса (по времени сервера)
/// </summary>
public DateTimeOffset LastTimeServer { get; set; }
/// <summary>
/// Дата первых данных в БД
/// </summary>
public DateTimeOffset TelemetryDateUtcMin { get; set; }
/// <summary>
/// Дата последних данных в БД
/// </summary>
public DateTimeOffset TelemetryDateUtcMax { get; set; }
}
private readonly ConcurrentDictionary<string, TrackerStat> telemetriesStats;
public TelemetryTracker(IConfiguration configuration, IMemoryCache memoryCache)
{
// TODO: make this background work
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql(configuration.GetConnectionString("DefaultConnection"))
.Options;
var db = new AsbCloudDbContext(contextOptions);
var cacheTelemetry = memoryCache.GetOrCreateBasic(db.Set<Telemetry>().Include(t=>t.Well));
var keyValuePairs = new Dictionary<string, TrackerStat>(cacheTelemetry.Count());
foreach (var telemetry in cacheTelemetry)
{
var date = telemetry.Info?.DrillingStartDate
?? ParseDateFromUidOrDefault(telemetry.RemoteUid, DateTimeOffset.MinValue);
keyValuePairs[telemetry.RemoteUid] = new TrackerStat
{
RemoteUid = telemetry.RemoteUid,
TelemetryDateUtcMin = date,
TelemetryDateUtcMax = date,
LastTimeServer = date,
};
}
telemetriesStats = new ConcurrentDictionary<string, TrackerStat>(keyValuePairs);
Task.Run(async () =>
{
db.Database.SetCommandTimeout(2 * 60);
var dates = await db.TelemetryDataSaub
.GroupBy(d => d.IdTelemetry)
.Select(g => new
{
IdTelemetry = g.Key,
DateMax = g.Max(d => d.DateTime),
DateMin = g.Min(d => d.DateTime),
})
.AsNoTracking()
.ToListAsync()
.ConfigureAwait(false);
var oldRequests = dates.Select(t => new
{
Uid = cacheTelemetry.FirstOrDefault(c => c.Id == t.IdTelemetry)?.RemoteUid,
t.DateMax,
t.DateMin,
}).Where(s => !string.IsNullOrEmpty(s.Uid));
foreach (var oldReq in oldRequests)
{
if (oldReq.Uid is not null)
{
var telemetryStat = telemetriesStats.GetOrAdd(oldReq.Uid, (uid) => new TrackerStat { RemoteUid = uid });
telemetryStat.TelemetryDateUtcMin = oldReq.DateMin;
telemetryStat.TelemetryDateUtcMax = oldReq.DateMax;
telemetryStat.LastTimeServer = oldReq.DateMax;
}
}
}).ContinueWith((t) =>
{
db.Dispose();
return t;
});
}
private static DateTimeOffset ParseDateFromUidOrDefault(string remoteUid, DateTimeOffset defaultValue = default)
{
//example: uid = 20211102_173407926
if (string.IsNullOrEmpty(remoteUid) || remoteUid.Length != 18)
return defaultValue;
if (DateTime.TryParseExact(remoteUid, "yyyyMMdd_HHmmssfff",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeUniversal,
out DateTime parsedDate))
return parsedDate;
return defaultValue;
}
public void SaveRequestDate(string uid, DateTimeOffset remoteDate)
{
var stat = telemetriesStats.GetOrAdd(uid, _ => new TrackerStat
{
RemoteUid = uid,
TelemetryDateUtcMin = remoteDate
}
);
stat.LastTimeServer = DateTime.Now;
if (stat.TelemetryDateUtcMax.ToUniversalTime() < remoteDate.ToUniversalTime())
stat.TelemetryDateUtcMax = remoteDate;
}
public DateTimeOffset GetLastTelemetryDateByUid(string uid) =>
telemetriesStats.GetValueOrDefault(uid)?.TelemetryDateUtcMax ?? default;
public DatesRangeDto GetTelemetryDateRangeByUid(string uid)
{
var stat = telemetriesStats.GetValueOrDefault(uid);
var range = new DatesRangeDto
{
From = stat?.TelemetryDateUtcMin.UtcDateTime ?? default,
To = stat?.TelemetryDateUtcMax.UtcDateTime ?? default,
};
return range;
}
public IEnumerable<string> GetTransmittingTelemetriesUids() =>
telemetriesStats.Keys;
}
}

View File

@ -1,13 +1,14 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMap;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Background;
using AsbCloudInfrastructure.Services.SAUB;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
@ -46,7 +47,8 @@ namespace AsbCloudInfrastructure.Services
var operationsStatService = serviceProvider.GetRequiredService<IOperationsStatService>();
var processMapRepository = serviceProvider.GetRequiredService<IProcessMapPlanRepository>();
var subsystemOperationTimeService = serviceProvider.GetRequiredService<ISubsystemOperationTimeService>();
var telemetryDataSaubCache = serviceProvider.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>();
var activeWells = await wellService.GetAsync(new() {IdState = 1}, token);
IEnumerable<int> activeWellsIds = activeWells
@ -56,21 +58,6 @@ namespace AsbCloudInfrastructure.Services
.Where(w => w.IdTelemetry != null)
.Select(t => t.IdTelemetry);
var lastTelemetryInfo = await db.TelemetryDataSaub
.Where(t => idTelemetries.Contains(t.IdTelemetry))
.Select(t => new
{
t.IdTelemetry,
t.WellDepth,
t.DateTime,
})
.GroupBy(t => t.IdTelemetry)
.Select(g => g.OrderByDescending(t => t.DateTime)
.First()
)
.AsNoTracking()
.ToArrayAsync(token);
var processMapRequests = activeWellsIds.Select(id => new ProcessMapRequest { IdWell = id });
var processMaps = await processMapRepository.GetProcessMapAsync(processMapRequests, token);
@ -83,43 +70,53 @@ namespace AsbCloudInfrastructure.Services
});
var operationsStat = await operationsStatService.GetWellsStatAsync(activeWellsIds, token);
var subsystemStat = await subsystemOperationTimeService.GetStatByActiveWells(activeWellsIds, token);
WellMapInfo = activeWells.Select(well => {
var wellMapInfo = well.Adapt<WellMapInfoWithComanies>();
var wellLastTelemetryInfo = lastTelemetryInfo.FirstOrDefault(t => t.IdTelemetry == well.IdTelemetry);
var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id);
var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id);
var wellLastFactSection = wellOperationsStat?.Sections.LastOrDefault(s => s.Fact is not null);
var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id);
double? currentDepth = null;
double? planTotalDepth = null;
DateTime lastTelemetryDate = default;
double currentDepth = wellLastTelemetryInfo?.WellDepth
?? wellLastFactSection?.Fact?.WellDepthEnd
?? 0d;
if (well.IdTelemetry.HasValue)
{
var lastSaubTelemetry = telemetryDataSaubCache.GetLastOrDefault(well.IdTelemetry.Value);
if(lastSaubTelemetry is not null)
{
currentDepth = lastSaubTelemetry.WellDepth;
lastTelemetryDate = lastSaubTelemetry.DateTime;
}
}
currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd;
var wellProcessMaps = processMaps
.Where(p => p.IdWell == well.Id)
.OrderBy(p => p.DepthEnd);
int? idSection = wellLastFactSection?.Id;
ProcessMapPlanDto? welllProcessMap = null;
ProcessMapPlanDto? welllProcessMap;
if (idSection is not null)
if (idSection.HasValue)
{
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
}
else
else if(currentDepth.HasValue)
{
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth && p.DepthEnd >= currentDepth);
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value);
idSection ??= welllProcessMap?.IdWellSectionType;
}
wellMapInfo.LastTelemetryDate = wellLastTelemetryInfo?.DateTime.ToRemoteDateTime(5) ?? new DateTime();
planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd;
planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd;
wellMapInfo.WellDepth = new()
{
Plan = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd,
Plan = planTotalDepth,
Fact = currentDepth,
};
@ -135,6 +132,7 @@ namespace AsbCloudInfrastructure.Services
Fact = wellOperationsStat?.Total.Fact?.RouteSpeed,
};
var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id);
wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAKB?.KUsage ?? 0d;
wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemSpinMaster?.KUsage ?? 0d;
wellMapInfo.TvdLagPercent = wellOperationsStat?.TvdLagDays ?? 0d;

View File

@ -151,7 +151,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
WellType = wellType?.Caption ?? "",
IdState = well.IdState,
State = wellService.GetStateText(well.IdState),
LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id).DateTime,
LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id),
Companies = await wellService.GetCompaniesAsync(well.Id, token)
};

View File

@ -57,15 +57,15 @@ namespace AsbCloudInfrastructure.Services
private void DropCacheRelationCompanyWell()
=> memoryCache.DropBasic<RelationCompanyWell>();
public DateTimeOffset GetLastTelemetryDate(int idWell)
public DateTime GetLastTelemetryDate(int idWell)
{
var well = GetOrDefault(idWell);
if (well?.IdTelemetry is null)
return DateTimeOffset.MinValue;
return DateTime.MinValue;
var lastTelemetryDate = telemetryService.GetLastTelemetryDate((int)well.IdTelemetry);
return lastTelemetryDate;
var datesRange = telemetryService.GetDatesRange(well.IdTelemetry.Value);
return datesRange.To;
}
/// <inheritdoc/>
@ -97,7 +97,7 @@ namespace AsbCloudInfrastructure.Services
dto.Latitude ??= gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
dto.Longitude ??= gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
if (well.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetLastTelemetryDate(well.IdTelemetry.Value);
dto.LastTelemetryDate = telemetryService.GetDatesRange(well.IdTelemetry.Value).To;
return dto;
}),
@ -256,7 +256,7 @@ namespace AsbCloudInfrastructure.Services
dto.Cluster = entity.Cluster.Caption;
dto.Deposit = entity.Cluster.Deposit.Caption;
if (entity.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetLastTelemetryDate((int)entity.IdTelemetry);
dto.LastTelemetryDate = telemetryService.GetDatesRange(entity.IdTelemetry.Value).To;
dto.Companies = entity.RelationCompaniesWells
.Select(r => Convert(r.Company))
.ToList();

View File

@ -10,6 +10,8 @@ using System;
using System.Threading.Tasks;
using System.Threading;
using AsbCloudInfrastructure.Background;
using AsbCloudApp.Data.SAUB;
using AsbCloudInfrastructure.Services.SAUB;
namespace AsbCloudInfrastructure
{
@ -28,6 +30,9 @@ namespace AsbCloudInfrastructure
var wellService = provider.GetRequiredService<IWellService>();
wellService.EnshureTimezonesIsSetAsync(CancellationToken.None).Wait();// TODO: make this background work
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>();
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSpinDto>>();
var backgroundWorker = provider.GetRequiredService<BackgroundWorker>();
backgroundWorker.Push(WellInfoService.MakeWork());
backgroundWorker.Push(OperationDetectionWorkFactory.MakeWork());
@ -45,7 +50,7 @@ namespace AsbCloudInfrastructure
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}");
System.Diagnostics.Trace.TraceInformation($"Total memory allocated is {bytesString} bytes. DbContext count is:{AsbCloudDbContext.ReferenceCount}");
return Task.CompletedTask;
};
var workPeriod = TimeSpan.FromMinutes(1);