using AsbCloudDb.Model; using AsbCloudDb.Model.Subsystems; using AsbCloudInfrastructure.Services.DetectOperations; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.Subsystems { internal class SubsystemOperationTimeBackgroundService : BackgroundService { private readonly string connectionString; private readonly TimeSpan period = TimeSpan.FromHours(1); public SubsystemOperationTimeBackgroundService(IConfiguration configuration) { connectionString = configuration.GetConnectionString("DefaultConnection"); } protected override async Task ExecuteAsync(CancellationToken token) { var timeToStartAnalysis = DateTime.Now; var options = new DbContextOptionsBuilder() .UseNpgsql(connectionString) .Options; while (!token.IsCancellationRequested) { if (DateTime.Now > timeToStartAnalysis) { timeToStartAnalysis = DateTime.Now + period; try { using var context = new AsbCloudDbContext(options); var added = await OperationTimeAllTelemetriesAsync(context, token); Trace.TraceInformation($"Total operation time subsystem complete. Added {added} operations time."); } 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 OperationTimeAllTelemetriesAsync(IAsbCloudDbContext db, CancellationToken token) { var lastDetectedDates = await db.DetectedOperations .GroupBy(o => o.IdTelemetry) .Select(g => new { IdTelemetry = g.Key, LastDate = g.Max(o => o.DateEnd) }) .ToListAsync(token); var telemetryIds = await db.Telemetries .Where(t => t.Info != null && t.TimeZone != null) .Select(t => t.Id) .ToListAsync(token); var JounedlastDetectedDates = telemetryIds .GroupJoin(lastDetectedDates, t => t, o => o.IdTelemetry, (outer, inner) => new { IdTelemetry = outer, inner.SingleOrDefault()?.LastDate, }); var affected = 0; foreach (var item in JounedlastDetectedDates) { var stopwatch = Stopwatch.StartNew(); var newOperations = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token); stopwatch.Stop(); if (newOperations.Any()) { db.SubsystemOperationTimes.AddRange(newOperations); affected += await db.SaveChangesAsync(token); } } return affected; } private static async Task> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) { var query = db.TelemetryDataSaub .AsNoTracking() .Where(d => d.IdTelemetry == idTelemetry) .Select(d => new OperationTimeData { DateTime = d.DateTime, Mode = d.Mode, Depth = d.WellDepth }) .OrderBy(d => d.DateTime); var take = 4 * 86_400; // 4 дня var startDate = begin; var resultSubsystemOperationTime = new List(); var firstItem = query.FirstOrDefault(); if (firstItem is null) return null; short? mode = firstItem.Mode; DateTimeOffset dateBegin = firstItem.DateTime; float? depthStart = firstItem.Depth; while (true) { var data = await query .Where(d => d.DateTime > startDate) .Take(take) .ToArrayAsync(token); for(int i = 1;i<=data.Length ;i++) { if( data[i].Mode!= mode) { var operationTimeItem = new SubsystemOperationTime() { IdTelemetry = idTelemetry, DateStart = dateBegin, DateEnd = data[i - 1].DateTime, DepthStart = depthStart, DepthEnd = data[i - 1].Depth }; resultSubsystemOperationTime.Add(operationTimeItem); mode = data[i].Mode; dateBegin = data[i].DateTime; depthStart = data[i].Depth; } } startDate = data.Last().DateTime; } return resultSubsystemOperationTime; } //private static async Task> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) //{ // var query = db.TelemetryDataSpin // .AsNoTracking() // .Where(d => d.IdTelemetry == idTelemetry) // .Select(d => new OperationTimeData // { // DateTime = d.DateTime, // Mode = d.Mode // // Depth = d.d // }) // .OrderBy(d => d.DateTime); // var take = 4 * 86_400; // 4 дня // var startDate = begin; // var operationTime = new List(); // const int minOperationLength = 5; // const int maxDetectorsInterpolationFrameLength = 30; // const int gap = maxDetectorsInterpolationFrameLength + minOperationLength; // while (true) // { // var data = await query // .Where(d => d.DateTime > startDate) // .Take(take) // .ToArrayAsync(token); // if (data.Length < gap) // break; // short? modeCount = data[0].Mode; // DateTimeOffset dateBegin = data[0].DateTime; // float? depthStart = data[0].Depth; // for (int i = 1; i <= data.Length; i++) // { // if (data[i].Mode != modeCount) // { // var operationTimeItem = new SubsystemOperationTime() // { // IdTelemetry = idTelemetry, // DateStart = dateBegin, // DateEnd = data[i - 1].DateTime, // DepthStart = depthStart, // DepthEnd = data[i - 1].Depth // }; // operationTime.Add(operationTimeItem); // modeCount = data[i].Mode; // dateBegin = data[i].DateTime; // depthStart = data[i].Depth; // } // } // } // var depths = db.TelemetryDataSaub.Where(t => true/*by date*/) // .GroupBy(t => t.IdTelemetry) // .Select(group => group.Min(t => t.WellDepth)); // return operationTime; //} } }