diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 055d742c..0946de01 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -6,7 +6,6 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Mapster; using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using AsbCloudInfrastructure.Background; using System.Threading; @@ -24,8 +23,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public CyclycArray LastData { get; init; } = null!; public double TimezoneHours { get; init; } = 5; } - - private IServiceProvider provider = null!; + private const int activeWellCapacity = 12 * 60 * 60; private const int doneWellCapacity = 65 * 60; @@ -56,7 +54,6 @@ namespace AsbCloudInfrastructure.Services.SAUB work.Timeout = TimeSpan.FromMinutes(15); worker.WorkStore.RunOnceQueue.Enqueue(work); } - instance.provider = provider; return instance; } @@ -70,10 +67,9 @@ namespace AsbCloudInfrastructure.Services.SAUB if (!range.Any()) return; - var newItems = range - .OrderBy(i => i.DateTime); + range = range.OrderBy(x => x.DateTime); - foreach (var item in newItems) + foreach (var item in range) item.IdTelemetry = idTelemetry; TelemetryDataCacheItem cacheItem; @@ -86,14 +82,14 @@ namespace AsbCloudInfrastructure.Services.SAUB } else { - cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() - { - FirstByDate = newItems.ElementAt(0), - LastData = new CyclycArray(activeWellCapacity) + cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() + { + FirstByDate = range.ElementAt(0), + LastData = new CyclycArray(activeWellCapacity) }); } - - cacheItem.LastData.AddRange(newItems); + + cacheItem.LastData.AddRange(range); } /// @@ -167,39 +163,44 @@ namespace AsbCloudInfrastructure.Services.SAUB private async Task InitializeCacheFromDBAsync(IAsbCloudDbContext db, Action onProgress, CancellationToken token) where TEntity : class, AsbCloudDb.Model.ITelemetryData { - if (isLoading) - throw new Exception("Multiple cache loading detected."); - - isLoading = true; - var defaultTimeout = db.Database.GetCommandTimeout(); db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); - Well[] wells = await db.Set() - .Include(well => well.Telemetry) - .Include(well => well.Cluster) - .Where(well => well.IdTelemetry != null) - .ToArrayAsync(token); + if (isLoading) + throw new Exception("Multiple cache loading detected."); - var count = wells.Length; - var i = 0d; - foreach (Well well in wells) - { - var capacity = well.IdState == 1 - ? activeWellCapacity - : doneWellCapacity; + try + { + isLoading = true; + + Well[] wells = await db.Set() + .Include(well => well.Telemetry) + .Include(well => well.Cluster) + .Where(well => well.IdTelemetry != null) + .ToArrayAsync(token); - var idTelemetry = well.IdTelemetry!.Value; - var hoursOffset = well.Timezone.Hours; + var count = wells.Length; + var i = 0d; + foreach (Well well in wells) + { + var capacity = well.IdState == 1 + ? activeWellCapacity + : doneWellCapacity; - onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count); - var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); - if (cacheItem is not null) - caches.TryAdd(idTelemetry, cacheItem); + var idTelemetry = well.IdTelemetry!.Value; + var hoursOffset = well.Timezone.Hours; + + onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count); + var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); + if (cacheItem is not null) + caches.TryAdd(idTelemetry, cacheItem); + } + } + finally + { + isLoading = false; + db.Database.SetCommandTimeout(defaultTimeout); } - - isLoading = false; - db.Database.SetCommandTimeout(defaultTimeout); } private static async Task GetOrDefaultCacheDataFromDbAsync(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token) @@ -249,12 +250,12 @@ namespace AsbCloudInfrastructure.Services.SAUB { if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return null; - + IEnumerable data = cacheItem.LastData; if (!data.Any()) return null; - + if (request.GeDate.HasValue) { var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); @@ -274,7 +275,7 @@ namespace AsbCloudInfrastructure.Services.SAUB var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); data = data.Where(d => d.DateTime >= request.LeDate); } - + 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); diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index 4417dd49..4cbf06fa 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -13,7 +13,7 @@ namespace AsbCloudInfrastructure.Services; public class WellboreService : IWellboreService { - const string WellboreNameFormat = "Ñòâîë {0}"; + const string WellboreNameFormat = "Ствол {0}"; private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; private readonly ITelemetryDataCache telemetryDataCache; diff --git a/AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs b/AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs new file mode 100644 index 00000000..94975e85 --- /dev/null +++ b/AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using AsbCloudApp.Data.SAUB; +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Background; +using AsbCloudInfrastructure.Services.SAUB; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Xunit; + +namespace AsbCloudWebApi.Tests.ServicesTests.SAUB; + +public class TelemetryDataSaubCacheTests +{ + private const int idTelemetry = 1; + + private readonly IEnumerable fakeTelemetries = new[] + { + new TelemetryDataSaubDto() + }; + + private readonly IServiceProvider serviceProviderMock = Substitute.For(); + + private readonly TelemetryDataCache telemetryDataCache; + private readonly Type telemetryDataCacheType; + + public TelemetryDataSaubCacheTests() + { + serviceProviderMock.GetService().Returns(new BackgroundWorker(serviceProviderMock)); + + telemetryDataCache = TelemetryDataCache.GetInstance(serviceProviderMock); + + telemetryDataCacheType = telemetryDataCache.GetType(); + } + + [Fact] + public void AddRange_ShouldReturn_AddedElementToCache() + { + //arrange + telemetryDataCacheType.GetField("isLoading", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(telemetryDataCache, false); + + //act + telemetryDataCache.AddRange(idTelemetry, fakeTelemetries); + var lastTelemetry = telemetryDataCache.GetLastOrDefault(idTelemetry); + + //assert + Assert.Equal(lastTelemetry, fakeTelemetries.Last()); + } + + [Fact] + public void AddRange_ShouldReturn_NotAddedToCache() + { + //arrange + telemetryDataCacheType.GetField("isLoading", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(telemetryDataCache, true); + + //act + telemetryDataCache.AddRange(idTelemetry, fakeTelemetries); + var lastTelemetry = telemetryDataCache.GetLastOrDefault(idTelemetry); + + //assert + Assert.NotEqual(lastTelemetry, fakeTelemetries.Last()); + } +} \ No newline at end of file