diff --git a/AsbCloudApp/Data/BackgroudWorkDto.cs b/AsbCloudApp/Data/BackgroundWorkDto.cs
similarity index 95%
rename from AsbCloudApp/Data/BackgroudWorkDto.cs
rename to AsbCloudApp/Data/BackgroundWorkDto.cs
index 64451d26..b2a3d161 100644
--- a/AsbCloudApp/Data/BackgroudWorkDto.cs
+++ b/AsbCloudApp/Data/BackgroundWorkDto.cs
@@ -6,7 +6,7 @@ namespace AsbCloudApp.Data
///
/// Информация о фоновой работе
///
- public class BackgroudWorkDto
+ public class BackgroundWorkDto
{
///
/// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки.
@@ -59,6 +59,11 @@ namespace AsbCloudApp.Data
///
public class LastErrorInfo : LastCompleteInfo
{
+ ///
+ ///
+ ///
+ ///
+ ///
public LastErrorInfo(CurrentStateInfo state, string errorText)
: base(state)
{
@@ -96,6 +101,10 @@ namespace AsbCloudApp.Data
///
public string State { get; init; }
+ ///
+ /// ctor
+ ///
+ ///
public LastCompleteInfo(CurrentStateInfo state)
{
Start = state.Start;
diff --git a/AsbCloudApp/Data/WellboreDto.cs b/AsbCloudApp/Data/WellboreDto.cs
index dbd9b697..c153b14f 100644
--- a/AsbCloudApp/Data/WellboreDto.cs
+++ b/AsbCloudApp/Data/WellboreDto.cs
@@ -7,7 +7,10 @@ namespace AsbCloudApp.Data;
///
public class WellboreDto
{
- public WellWithTimezoneDto Well { get; set; }
+ ///
+ /// Скважина
+ ///
+ public WellWithTimezoneDto Well { get; set; } = null!;
///
/// Идентификатор
diff --git a/AsbCloudApp/Services/Notifications/NotificationService.cs b/AsbCloudApp/Services/Notifications/NotificationService.cs
index 85c521e3..4537f04e 100644
--- a/AsbCloudApp/Services/Notifications/NotificationService.cs
+++ b/AsbCloudApp/Services/Notifications/NotificationService.cs
@@ -90,7 +90,6 @@ public class NotificationService
/// Отправка уведомлений, которые не были отправлены
///
///
- ///
///
///
public async Task RenotifyAsync(int idUser, CancellationToken cancellationToken)
diff --git a/AsbCloudInfrastructure/Background/BackgroundWorker.cs b/AsbCloudInfrastructure/Background/BackgroundWorker.cs
index f4ef8c0e..cacb5a60 100644
--- a/AsbCloudInfrastructure/Background/BackgroundWorker.cs
+++ b/AsbCloudInfrastructure/Background/BackgroundWorker.cs
@@ -40,7 +40,7 @@ public class BackgroundWorker : BackgroundService
var result = await work.Start(scope.ServiceProvider, token);
if (!result)
- WorkStore.Falled.Add(work);
+ WorkStore.Felled.Add(work);
CurrentWork = null;
await Task.Delay(minDelay, token);
diff --git a/AsbCloudInfrastructure/Background/Work.cs b/AsbCloudInfrastructure/Background/Work.cs
index 84135707..9372343b 100644
--- a/AsbCloudInfrastructure/Background/Work.cs
+++ b/AsbCloudInfrastructure/Background/Work.cs
@@ -3,86 +3,96 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-namespace AsbCloudInfrastructure.Background
+namespace AsbCloudInfrastructure.Background;
+
+///
+/// Класс разовой работы.
+/// Разовая работа приоритетнее периодической.
+///
+public abstract class Work : BackgroundWorkDto
{
- ///
- /// Класс разовой работы.
- /// Разовая работа приоритетнее периодической.
- ///
- public class Work : BackgroudWorkDto
+ private sealed class WorkBase : Work
{
private Func, CancellationToken, Task> ActionAsync { get; }
-
- ///
- /// Делегат обработки ошибки.
- /// Не должен выполняться долго.
- ///
- public Func? OnErrorAsync { get; set; }
-
- public TimeSpan OnErrorHandlerTimeout { get; set; } = TimeSpan.FromSeconds(5);
-
- ///
- /// Базовая работа
- ///
- ///
- ///
- /// Делегат работы.
- ///
- /// Параметры:
- ///
- /// -
- /// string
- /// Id Идентификатор работы
- ///
- /// -
- /// IServiceProvider
- /// Поставщик сервисов
- ///
- /// -
- /// Action<string, double?>
- /// on progress callback. String - new state text. double? - optional progress 0-100%.
- ///
- /// -
- /// CancellationToken
- /// Токен отмены задачи
- ///
- ///
- ///
- ///
- public Work(string id, Func, CancellationToken, Task> actionAsync)
+ public WorkBase(string id, Func, CancellationToken, Task> actionAsync)
+ : base(id)
{
- Id = id;
ActionAsync = actionAsync;
}
-
- ///
- /// Запустить работу
- ///
- ///
- ///
- /// True - susess, False = Fail
- public async Task Start(IServiceProvider services, CancellationToken token)
- {
- SetStatusStart();
- try
- {
- var task = ActionAsync(Id, services, UpdateStatus, token);
- await task.WaitAsync(Timeout, token);
- SetStatusComplete();
- return true;
- }
- catch (Exception exception)
- {
- SetLastError(exception.Message);
- if (OnErrorAsync is not null)
- {
- var task = Task.Run(
- async () => await OnErrorAsync(Id, exception, token),
- token);
- await task.WaitAsync(OnErrorHandlerTimeout, token);
- }
- }
- return false;
- }
+
+ protected override Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token)
+ => ActionAsync(id, services, onProgressCallback, token);
}
+
+ ///
+ /// Делегат обработки ошибки.
+ /// Не должен выполняться долго.
+ ///
+ public Func? OnErrorAsync { get; set; }
+
+ ///
+ /// макс продолжительность обработки исключения
+ ///
+ public TimeSpan OnErrorHandlerTimeout { get; set; } = TimeSpan.FromSeconds(5);
+
+ ///
+ /// Базовая работа
+ ///
+ ///
+ public Work(string id)
+ {
+ Id = id;
+ }
+
+ ///
+ /// Создать работу на основе делегата
+ ///
+ ///
+ ///
+ ///
+ [Obsolete("Use implement Work class")]
+ public static Work CreateByDelegate(string id, Func, CancellationToken, Task> actionAsync)
+ {
+ return new WorkBase(id, actionAsync);
+ }
+
+ ///
+ /// Запустить работу
+ ///
+ ///
+ ///
+ /// True - success, False = fail
+ public async Task Start(IServiceProvider services, CancellationToken token)
+ {
+ SetStatusStart();
+ try
+ {
+ var task = Action(Id, services, UpdateStatus, token);
+ await task.WaitAsync(Timeout, token);
+ SetStatusComplete();
+ return true;
+ }
+ catch (Exception exception)
+ {
+ SetLastError(exception.Message);
+ if (OnErrorAsync is not null)
+ {
+ var task = Task.Run(
+ async () => await OnErrorAsync(Id, exception, token),
+ token);
+ await task.WaitAsync(OnErrorHandlerTimeout, token);
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// делегат фоновой работы
+ ///
+ /// Идентификатор работы
+ /// Поставщик сервисов
+ /// on progress callback. String - new state text. double? - optional progress 0-100%
+ ///
+ ///
+ protected abstract Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token);
}
diff --git a/AsbCloudInfrastructure/Background/WorkStore.cs b/AsbCloudInfrastructure/Background/WorkStore.cs
index dbb1e464..b57fc104 100644
--- a/AsbCloudInfrastructure/Background/WorkStore.cs
+++ b/AsbCloudInfrastructure/Background/WorkStore.cs
@@ -18,16 +18,35 @@ public class WorkStore
/// Список периодических задач
///
public IEnumerable Periodics => periodics;
+
///
/// Работы выполняемые один раз
///
public Queue RunOnceQueue { get; private set; } = new(8);
///
- /// Завершывшиеся с ошибкой
+ /// Завершившиеся с ошибкой
///
- public CyclycArray Falled { get; } = new(16);
-
+ public CyclycArray Felled { get; } = new(16);
+
+ ///
+ /// Добавить фоновую работу выполняющуюся с заданным периодом
+ ///
+ ///
+ ///
+ public void AddPeriodic(TimeSpan period)
+ where T : Work, new()
+ {
+ var work = new T();
+ var periodic = new WorkPeriodic(work, period);
+ periodics.Add(periodic);
+ }
+
+ ///
+ /// Добавить фоновую работу выполняющуюся с заданным периодом
+ ///
+ ///
+ ///
public void AddPeriodic(Work work, TimeSpan period)
{
var periodic = new WorkPeriodic(work, period);
diff --git a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs
index 2f402285..03ed6e07 100644
--- a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs
+++ b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs
@@ -226,7 +226,7 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
.OrderBy(w => w.DateStart);
}
- private Task?> GetSubsystemStatsAsync(int idWell, DateTime startDate,
+ private Task> GetSubsystemStatsAsync(int idWell, DateTime startDate,
DateTime finishDate, CancellationToken cancellationToken)
{
var request = new SubsystemOperationTimeRequest
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs b/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs
deleted file mode 100644
index 0c9bb3dd..00000000
--- a/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionWorkFactory.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-using AsbCloudDb.Model;
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
-using AsbCloudInfrastructure.Background;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace AsbCloudInfrastructure.Services.DetectOperations
-{
-
- public static class OperationDetectionWorkFactory
- {
- private const string workId = "Operation detection";
- private static string progress = "no progress";
-
- private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
- {
- new DetectorRotor(),
- new DetectorSlide(),
- //new DetectorDevelopment(),
- //new DetectorTemplating(),
- new DetectorSlipsTime(),
- //new DetectorStaticSurveying(),
- //new DetectorFlashingBeforeConnection(),
- //new DetectorFlashing(),
- //new DetectorTemplatingWhileDrilling(),
- };
-
- public static Work MakeWork() => new Work(workId, WorkAction)
- {
- Timeout = TimeSpan.FromMinutes(20),
- OnErrorAsync = (id, exception, token) =>
- {
- var text = $"work {id}, when {progress}, throw error:{exception.Message}";
- Trace.TraceWarning(text);
- return Task.CompletedTask;
- }
- };
-
- // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
- private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action onProgress, CancellationToken token)
- {
- using var db = serviceProvider.GetRequiredService();
-
- 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 joinedlastDetectedDates = telemetryIds
- .GroupJoin(lastDetectedDates,
- t => t,
- o => o.IdTelemetry,
- (outer, inner) => new
- {
- IdTelemetry = outer,
- inner.SingleOrDefault()?.LastDate,
- });
-
- var affected = 0;
- var count = joinedlastDetectedDates.Count();
- var i = 0;
- foreach (var item in joinedlastDetectedDates)
- {
- var stopwatch = Stopwatch.StartNew();
- var startDate = item.LastDate ?? DateTimeOffset.MinValue;
- onProgress($"start detecting telemetry: {item.IdTelemetry} from {startDate}", i++ / count);
- var newOperations = await DetectOperationsAsync(item.IdTelemetry, startDate, db, token);
- stopwatch.Stop();
- if (newOperations.Any())
- {
- db.DetectedOperations.AddRange(newOperations);
- affected += await db.SaveChangesAsync(token);
- }
- }
- }
-
- private static async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
- {
- var query = db.TelemetryDataSaub
- .AsNoTracking()
- .Where(d => d.IdTelemetry == idTelemetry)
- .Where(d => d.BlockPosition >= 0)
- .Select(d => new DetectableTelemetry
- {
- DateTime = d.DateTime,
- IdUser = d.IdUser,
- WellDepth = d.WellDepth ?? float.NaN,
- Pressure = d.Pressure ?? float.NaN,
- HookWeight = d.HookWeight ?? float.NaN,
- BlockPosition = d.BlockPosition ?? float.NaN,
- BitDepth = d.BitDepth ?? float.NaN,
- RotorSpeed = d.RotorSpeed ?? float.NaN,
- })
- .OrderBy(d => d.DateTime);
-
- var take = 4 * 86_400; // 4 дня
- var startDate = begin;
- var detectedOperations = new List(8);
- DetectedOperation? lastDetectedOperation = null;
- 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;
-
- var isDetected = false;
- var positionBegin = 0;
- var positionEnd = data.Length - gap;
- var step = 10;
- while (positionEnd > positionBegin)
- {
- step ++;
- for (int i = 0; i < detectors.Length; i++)
- {
- progress = $"telemetry:{idTelemetry}, date:{startDate}, pos:{positionBegin}, detector:{detectors[i]}";
- if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult? result))
- {
- detectedOperations.Add(result!.Operation);
- lastDetectedOperation = result.Operation;
- isDetected = true;
- step = 1;
- positionBegin = result.TelemetryEnd;
- break;
- }
- }
- if (step > 20)
- step = 10;
- positionBegin += step;
- }
-
- if (isDetected)
- startDate = lastDetectedOperation!.DateEnd;
- else
- startDate = data[positionEnd].DateTime;
- }
-
- return detectedOperations;
- }
- }
-
-}
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs
new file mode 100644
index 00000000..eef423b9
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs
@@ -0,0 +1,157 @@
+using AsbCloudDb.Model;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
+using AsbCloudInfrastructure.Background;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace AsbCloudInfrastructure.Services.DetectOperations;
+
+public class WorkOperationDetection: Work
+{
+ private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
+ {
+ new DetectorRotor(),
+ new DetectorSlide(),
+ //new DetectorDevelopment(),
+ //new DetectorTemplating(),
+ new DetectorSlipsTime(),
+ //new DetectorStaticSurveying(),
+ //new DetectorFlashingBeforeConnection(),
+ //new DetectorFlashing(),
+ //new DetectorTemplatingWhileDrilling(),
+ };
+
+ public WorkOperationDetection()
+ :base("Operation detection")
+ {
+ Timeout = TimeSpan.FromMinutes(20);
+ OnErrorAsync = (id, exception, token) =>
+ {
+ var text = $"work {id}, when {CurrentState?.State}, throw error:{exception.Message}";
+ Trace.TraceWarning(text);
+ return Task.CompletedTask;
+ };
+ }
+
+ protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token)
+ {
+ using var db = services.GetRequiredService();
+
+ 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 joinedlastDetectedDates = telemetryIds
+ .GroupJoin(lastDetectedDates,
+ t => t,
+ o => o.IdTelemetry,
+ (outer, inner) => new
+ {
+ IdTelemetry = outer,
+ inner.SingleOrDefault()?.LastDate,
+ });
+
+ var affected = 0;
+ var count = joinedlastDetectedDates.Count();
+ var i = 0d;
+ foreach (var item in joinedlastDetectedDates)
+ {
+ var stopwatch = Stopwatch.StartNew();
+ var startDate = item.LastDate ?? DateTimeOffset.MinValue;
+ onProgressCallback($"start detecting telemetry: {item.IdTelemetry} from {startDate}", i++ / count);
+ var newOperations = await DetectOperationsAsync(item.IdTelemetry, startDate, db, token);
+ stopwatch.Stop();
+ if (newOperations.Any())
+ {
+ db.DetectedOperations.AddRange(newOperations);
+ affected += await db.SaveChangesAsync(token);
+ }
+ }
+ }
+
+ private static async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
+ {
+ var query = db.TelemetryDataSaub
+ .AsNoTracking()
+ .Where(d => d.IdTelemetry == idTelemetry)
+ .Where(d => d.BlockPosition >= 0)
+ .Select(d => new DetectableTelemetry
+ {
+ DateTime = d.DateTime,
+ IdUser = d.IdUser,
+ WellDepth = d.WellDepth ?? float.NaN,
+ Pressure = d.Pressure ?? float.NaN,
+ HookWeight = d.HookWeight ?? float.NaN,
+ BlockPosition = d.BlockPosition ?? float.NaN,
+ BitDepth = d.BitDepth ?? float.NaN,
+ RotorSpeed = d.RotorSpeed ?? float.NaN,
+ })
+ .OrderBy(d => d.DateTime);
+
+ var take = 4 * 86_400; // 4 дня
+ var startDate = begin;
+ var detectedOperations = new List(8);
+ DetectedOperation? lastDetectedOperation = null;
+ 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;
+
+ var isDetected = false;
+ var positionBegin = 0;
+ var positionEnd = data.Length - gap;
+ var step = 10;
+ while (positionEnd > positionBegin)
+ {
+ step ++;
+ for (int i = 0; i < detectors.Length; i++)
+ {
+ if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult? result))
+ {
+ detectedOperations.Add(result!.Operation);
+ lastDetectedOperation = result.Operation;
+ isDetected = true;
+ step = 1;
+ positionBegin = result.TelemetryEnd;
+ break;
+ }
+ }
+ if (step > 20)
+ step = 10;
+ positionBegin += step;
+ }
+
+ if (isDetected)
+ startDate = lastDetectedOperation!.DateEnd;
+ else
+ startDate = data[positionEnd].DateTime;
+ }
+
+ return detectedOperations;
+ }
+}
diff --git a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs
index 402a89ed..228a3564 100644
--- a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs
+++ b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs
@@ -540,11 +540,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
return Task.CompletedTask;
};
- var work = new Work(workId, workAction)
- {
- OnErrorAsync = onErrorAction
- };
-
+ var work = Work.CreateByDelegate(workId, workAction);
+ work.OnErrorAsync = onErrorAction;
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
}
}
diff --git a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs
index 33f011bf..bbbc8196 100644
--- a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs
+++ b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs
@@ -56,7 +56,7 @@ namespace AsbCloudInfrastructure.Services.Email
{
var workAction = MakeEmailSendWorkAction(notification);
- var work = new Work(workId, workAction);
+ var work = Work.CreateByDelegate(workId, workAction);
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
}
diff --git a/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs b/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs
deleted file mode 100644
index 07a17369..00000000
--- a/AsbCloudInfrastructure/Services/LimitingParameterBackgroundService.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using AsbCloudDb.Model;
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Data.Common;
-using System.Data;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using AsbCloudInfrastructure.Background;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace AsbCloudInfrastructure.Services
-{
-
- internal static class LimitingParameterCalcWorkFactory
- {
- private const string workId = "Limiting parameter calc";
-
- public static Work MakeWork() => new Work(workId, WorkAction)
- {
- Timeout = TimeSpan.FromMinutes(30)
- };
-
- // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
- private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action onProgress, CancellationToken token)
- {
- using var db = serviceProvider.GetRequiredService();
- var lastDetectedDates = await db.LimitingParameter
- .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 telemetryLastDetectedDates = telemetryIds
- .GroupJoin(lastDetectedDates,
- t => t,
- o => o.IdTelemetry,
- (outer, inner) => new
- {
- IdTelemetry = outer,
- inner.SingleOrDefault()?.LastDate,
- });
-
- var count = telemetryLastDetectedDates.Count();
- var i = 0;
- foreach (var item in telemetryLastDetectedDates)
- {
- onProgress($"Start hanling telemetry: {item.IdTelemetry} from {item.LastDate}", i++/count);
- var newLimitingParameters = await GetLimitingParameterAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
- if (newLimitingParameters?.Any() == true)
- {
- db.LimitingParameter.AddRange(newLimitingParameters);
- await db.SaveChangesAsync(token);
- }
- }
- }
-
- private static async Task> GetLimitingParameterAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
- {
- var query =
- $"select " +
- $"limiting_parameters.date, limiting_parameters.id_feed_regulator, limiting_parameters.well_depth " +
- $"from ( " +
- $"select " +
- $"date, id_feed_regulator, well_depth, " +
- $"lag(id_feed_regulator, 1) over (order by date) as id_feed_regulator_lag, " +
- $"lead(id_feed_regulator, 1) over (order by date) as id_feed_regulator_lead " +
- $"from t_telemetry_data_saub " +
- $"where id_feed_regulator is not null " +
- $"and id_telemetry = {idTelemetry}" +
- $"and date >= '{begin:u}'" +
- $"order by date) as limiting_parameters " +
- $"where id_feed_regulator_lag is null " +
- $"or (id_feed_regulator != id_feed_regulator_lag and id_feed_regulator_lead != id_feed_regulator_lag) " +
- $"order by date;";
-
- var limitingParameters = new List(32);
- using (var result = await ExecuteReaderAsync(db, query, token))
- {
- LimitingParameter? limitingLast = null;
- while (result.Read())
- {
- var date = result.GetFieldValue(0);
- var idLimiting = result.GetFieldValue(1);
- var wellDepth = result.GetFieldValue(2);
-
- if (limitingLast is null)
- {
- limitingLast = new LimitingParameter
- {
- DateStart = date,
- DepthStart = wellDepth,
- IdFeedRegulator = idLimiting
- };
- }
-
- if (limitingLast.IdFeedRegulator != idLimiting || limitingLast.DepthStart < wellDepth)
- {
- limitingParameters.Add(new LimitingParameter {
- IdTelemetry = idTelemetry,
- IdFeedRegulator = limitingLast.IdFeedRegulator,
- DateStart = limitingLast.DateStart,
- DateEnd = date,
- DepthStart = limitingLast.DepthStart,
- DepthEnd = wellDepth
- });
-
- limitingLast = new LimitingParameter
- {
- DateStart = date,
- DepthStart = wellDepth,
- IdFeedRegulator = idLimiting
- };
- }
- }
- }
-
- return limitingParameters;
- }
-
- private static async Task ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
- {
- var connection = db.Database.GetDbConnection();
- if (
- connection?.State is null ||
- connection.State == ConnectionState.Broken ||
- connection.State == ConnectionState.Closed)
- {
- await db.Database.OpenConnectionAsync(token);
- connection = db.Database.GetDbConnection();
- }
- using var command = connection.CreateCommand();
- command.CommandText = query;
-
- var result = await command.ExecuteReaderAsync(token);
- return result;
- }
- }
-
-}
diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs
index f3ab6cb8..6a66c30e 100644
--- a/AsbCloudInfrastructure/Services/ReportService.cs
+++ b/AsbCloudInfrastructure/Services/ReportService.cs
@@ -94,7 +94,7 @@ namespace AsbCloudInfrastructure.Services
context.SaveChanges();
};
- var work = new Work(workId, workAction);
+ var work = Work.CreateByDelegate(workId, workAction);
backgroundWorkerService.WorkStore.RunOnceQueue.Enqueue(work);
progressHandler.Invoke(new ReportProgressDto
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
index daaa2dcf..9bb2dc79 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
@@ -48,7 +48,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
instance = new TelemetryDataCache();
var worker = provider.GetRequiredService();
var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}";
- var work = new Work(workId, async (workId, provider, onProgress, token) => {
+ var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => {
var db = provider.GetRequiredService();
await instance.InitializeCacheFromDBAsync(db, onProgress, token);
});
@@ -159,7 +159,6 @@ namespace AsbCloudInfrastructure.Services.SAUB
isLoading = true;
var defaultTimeout = db.Database.GetCommandTimeout();
- System.Diagnostics.Trace.TraceInformation($"cache loading starting. Setting CommandTimeout 90s ({defaultTimeout})");
db.Database.SetCommandTimeout(TimeSpan.FromSeconds(90));
Well[] wells = await db.Set()
@@ -169,7 +168,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
.ToArrayAsync(token);
var count = wells.Length;
- var i = 0;
+ var i = 0d;
foreach (Well well in wells)
{
var capacity = well.IdState == 1
@@ -178,21 +177,13 @@ namespace AsbCloudInfrastructure.Services.SAUB
var idTelemetry = well.IdTelemetry!.Value;
var hoursOffset = well.Timezone.Hours;
- // TODO: remove traces
- System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}>: Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}");
+
+ 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);
- 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;
db.Database.SetCommandTimeout(defaultTimeout);
}
diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs
deleted file mode 100644
index 451ca633..00000000
--- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeCalcWorkFactory.cs
+++ /dev/null
@@ -1,298 +0,0 @@
-using AsbCloudDb.Model;
-using AsbCloudDb.Model.Subsystems;
-using AsbCloudInfrastructure.Background;
-using AsbCloudInfrastructure.Services.Subsystems.Utils;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Data.Common;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace AsbCloudInfrastructure.Services.Subsystems
-{
- internal static class SubsystemOperationTimeCalcWorkFactory
- {
- private const string workId = "Subsystem operation time calc";
-
- private const int idSubsytemTorqueMaster = 65537;
- private const int idSubsytemSpinMaster = 65536;
- private const int idSubsystemAPDRotor = 11;
- private const int idSubsystemAPDSlide = 12;
- private const int idSubsytemMse = 2;
-
- public static Work MakeWork() => new Work(workId, WorkAction)
- {
- Timeout = TimeSpan.FromMinutes(20)
- };
-
- // TODO: Разделить этот акшн на более мелкие части И использовать telemetryServiceData<..> вместо прямого обращения к БД.
- private static async Task WorkAction(string _, IServiceProvider serviceProvider, Action onProgress, CancellationToken token)
- {
- using var db = serviceProvider.GetRequiredService();
-
- var lastDetectedDates = await db.SubsystemOperationTimes
- .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 telemetryLastDetectedDates = telemetryIds
- .GroupJoin(lastDetectedDates,
- t => t,
- o => o.IdTelemetry,
- (outer, inner) => new
- {
- IdTelemetry = outer,
- inner.SingleOrDefault()?.LastDate,
- });
-
- var count = telemetryLastDetectedDates.Count();
- var i = 0;
- foreach (var item in telemetryLastDetectedDates)
- {
- onProgress($"Start hanling telemetry: {item.IdTelemetry} from {item.LastDate}", i++ / count);
- var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
- if (newOperationsSaub?.Any() == true)
- {
- db.SubsystemOperationTimes.AddRange(newOperationsSaub);
- await db.SaveChangesAsync(token);
- }
- var newOperationsSpin = await OperationTimeSpinAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
- if (newOperationsSpin?.Any() == true)
- {
- db.SubsystemOperationTimes.AddRange(newOperationsSpin);
- await db.SaveChangesAsync(token);
- }
- }
- }
-
- private static async Task ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
- {
- var connection = db.Database.GetDbConnection();
- if (
- connection?.State is null ||
- connection.State == ConnectionState.Broken ||
- connection.State == ConnectionState.Closed)
- {
- await db.Database.OpenConnectionAsync(token);
- connection = db.Database.GetDbConnection();
- }
- using var command = connection.CreateCommand();
- command.CommandText = query;
-
- var result = await command.ExecuteReaderAsync(token);
- return result;
- }
-
- private static async Task> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
- {
- static bool isSubsytemAkbRotor(short? mode) => mode == 1;
-
- static bool isSubsytemAkbSlide(short? mode) => mode == 3;
-
- static bool IsSubsystemMse(short? state) => (state & 1) > 0;
-
- var query =
- $"select tt.date, tt.mode, tt.well_depth, tt.mse_state " +
- $"from ( " +
- $" select " +
- $" date, " +
- $" mode, " +
- $" mse_state, " +
- $" well_depth, " +
- $" lag(mode,1) over (order by date) as mode_lag, " +
- $" lead(mode,1) over (order by date) as mode_lead " +
- $" from t_telemetry_data_saub " +
- $" where id_telemetry = {idTelemetry} and well_depth is not null and well_depth > 0" +
- $" order by date ) as tt " +
- $"where (tt.mode_lag is null or (tt.mode != tt.mode_lag and tt.mode_lead != tt.mode_lag)) and tt.date >= '{begin:u}' " +
- $"order by tt.date;";
-
- using var result = await ExecuteReaderAsync(db, query, token);
-
- var subsystemsOperationTimes = new List();
- var detectorRotor = new SubsystemDetector(idTelemetry, idSubsystemAPDRotor, isSubsytemAkbRotor, IsValid);
- var detectorSlide = new SubsystemDetector(idTelemetry, idSubsystemAPDSlide, isSubsytemAkbSlide, IsValid);
- var detectorMse = new SubsystemDetector(idTelemetry, idSubsytemMse, IsSubsystemMse, IsValid);
-
- while (result.Read())
- {
- var mode = result.GetFieldValue(1);
- var state = result.GetFieldValue(3);
-
- var isAkbRotorEnable = isSubsytemAkbRotor(mode);
- var isAkbSlideEnable = isSubsytemAkbSlide(mode);
- var isMseEnable = IsSubsystemMse(state);
- var date = result.GetFieldValue(0);
- var depth = result.GetFieldValue(2);
-
- if (detectorRotor.TryDetect(mode, date, depth, out var detectedRotor))
- subsystemsOperationTimes.Add(detectedRotor!);
-
- if (detectorSlide.TryDetect(mode, date, depth, out var detectedSlide))
- subsystemsOperationTimes.Add(detectedSlide!);
-
- if (detectorMse.TryDetect(mode, date, depth, out var detectedMse))
- subsystemsOperationTimes.Add(detectedMse!);
- }
-
- return subsystemsOperationTimes;
- }
-
- private static async Task> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
- {
- static int? GetSubsytemId(short? mode, int? state)
- {
- // При изменении следующего кода сообщи в Vladimir.Sobolev@nedra.digital
- if (state == 7 && (mode & 2) > 0)
- return idSubsytemTorqueMaster;// демпфер
-
- if (state != 0 && state != 5 && state != 6 && state != 7)
- return idSubsytemSpinMaster;// осцилляция
-
- return null;
- }
-
- var querySpin =
- $"select " +
- $" tspin.date, " +
- $" tspin.mode, " +
- $" tspin.state " +
- $"from ( " +
- $" select " +
- $" date, " +
- $" mode, " +
- $" lag(mode, 1) over (order by date) as mode_lag, " +
- $" lead(mode, 1) over (order by date) as mode_lead, " +
- $" state, " +
- $" lag(state, 1) over (order by date) as state_lag " +
- $" from t_telemetry_data_spin " +
- $" where id_telemetry = {idTelemetry} and date >= '{begin:u}'" +
- $" order by date ) as tspin " +
- $"where mode_lag is null or state_lag is null or (mode != mode_lag and mode_lead != mode_lag) or state != state_lag " +
- $"order by date;";
-
- var rows = new List<(int? IdSubsystem, DateTimeOffset Date)>(32);
-
- using var resultSpin = await ExecuteReaderAsync(db, querySpin, token);
- int? idSubsystemLast = null;
- while (resultSpin.Read())
- {
- var mode = resultSpin.GetFieldValue(1);
- var state = resultSpin.GetFieldValue(2);
- var idSubsystem = GetSubsytemId(mode, state);
- if (idSubsystemLast != idSubsystem)
- {
- idSubsystemLast = idSubsystem;
- var date = resultSpin.GetFieldValue(0);
- rows.Add((idSubsystem, date));
- }
- }
- await resultSpin.DisposeAsync();
-
- if (rows.Count < 2)
- return Enumerable.Empty();
-
- var minSpinDate = rows.Min(i => i.Date);
- var maxSpinDate = rows.Max(i => i.Date);
- var depthInterpolation = await GetInterpolation(db, idTelemetry, minSpinDate, maxSpinDate, token);
-
- if (depthInterpolation is null)
- return Enumerable.Empty();
-
- var subsystemsOperationTimes = new List(32);
-
- for (int i = 1; i < rows.Count; i++)
- {
- var r0 = rows[i - 1];
- var r1 = rows[i];
- if (r0.IdSubsystem is not null && r0.IdSubsystem != r1.IdSubsystem)
- {
- var subsystemOperationTime = new SubsystemOperationTime()
- {
- IdTelemetry = idTelemetry,
- IdSubsystem = r0.IdSubsystem.Value,
- DateStart = r0.Date,
- DateEnd = r1.Date,
- DepthStart = depthInterpolation.GetDepth(r0.Date),
- DepthEnd = depthInterpolation.GetDepth(r1.Date),
- };
-
- if (IsValid(subsystemOperationTime))
- subsystemsOperationTimes.Add(subsystemOperationTime);
- }
- }
-
- return subsystemsOperationTimes;
- }
-
- private static bool IsValid(SubsystemOperationTime item)
- {
- var validateCode = GetValidateErrorCode(item);
- if (validateCode != 0)
- {
- var str = System.Text.Json.JsonSerializer.Serialize(item);
- Trace.TraceWarning($"Wrong({validateCode}) SubsystemOperationTime: {str}");
- }
- return validateCode == 0;
- }
-
- private static int GetValidateErrorCode(SubsystemOperationTime item)
- {
- if (item.DateStart > item.DateEnd)
- return -1;
- if ((item.DateEnd - item.DateStart).TotalHours > 48)
- return -2;
- if (item.DepthEnd < item.DepthStart)
- return -3;
- if (item.DepthEnd - item.DepthStart > 2000d)
- return -4;
- if (item.DepthEnd < 0d)
- return -5;
- if (item.DepthStart < 0d)
- return -6;
- if (item.DepthEnd > 24_0000d)
- return -7;
- if (item.DepthStart > 24_0000d)
- return -8;
- return 0;
- }
-
- private static async Task GetInterpolation(IAsbCloudDbContext db, int idTelemetry, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
- {
- var dataDepthFromSaub = await db.TelemetryDataSaub
- .Where(d => d.IdTelemetry == idTelemetry)
- .Where(d => d.DateTime >= dateBegin)
- .Where(d => d.DateTime <= dateEnd)
- .Where(d => d.WellDepth != null)
- .Where(d => d.WellDepth > 0)
- .GroupBy(d => Math.Ceiling(d.WellDepth ?? 0 * 10))
- .Select(g => new {
- DateMin = g.Min(d => d.DateTime),
- DepthMin = g.Min(d => d.WellDepth) ?? 0,
- })
- .OrderBy(i => i.DateMin)
- .ToArrayAsync(token);
-
- if (!dataDepthFromSaub.Any())
- return null;
-
- var depthInterpolation = new DepthInterpolation(dataDepthFromSaub.Select(i => (i.DateMin, i.DepthMin)));
- return depthInterpolation;
- }
- }
-
-}
diff --git a/AsbCloudInfrastructure/Services/Subsystems/WorkSubsystemOperationTimeCalc.cs b/AsbCloudInfrastructure/Services/Subsystems/WorkSubsystemOperationTimeCalc.cs
new file mode 100644
index 00000000..bda4bbe4
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/Subsystems/WorkSubsystemOperationTimeCalc.cs
@@ -0,0 +1,294 @@
+using AsbCloudDb.Model;
+using AsbCloudDb.Model.Subsystems;
+using AsbCloudInfrastructure.Background;
+using AsbCloudInfrastructure.Services.Subsystems.Utils;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsbCloudInfrastructure.Services.Subsystems;
+
+public class WorkSubsystemOperationTimeCalc: Work
+{
+ private const int idSubsytemTorqueMaster = 65537;
+ private const int idSubsytemSpinMaster = 65536;
+ private const int idSubsystemAPDRotor = 11;
+ private const int idSubsystemAPDSlide = 12;
+ private const int idSubsytemMse = 2;
+
+ public WorkSubsystemOperationTimeCalc()
+ : base("Subsystem operation time calc")
+ {
+ Timeout = TimeSpan.FromMinutes(20);
+ }
+
+ protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token)
+ {
+ using var db = services.GetRequiredService();
+
+ var lastDetectedDates = await db.SubsystemOperationTimes
+ .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 telemetryLastDetectedDates = telemetryIds
+ .GroupJoin(lastDetectedDates,
+ t => t,
+ o => o.IdTelemetry,
+ (outer, inner) => new
+ {
+ IdTelemetry = outer,
+ inner.SingleOrDefault()?.LastDate,
+ });
+
+ var count = telemetryLastDetectedDates.Count();
+ var i = 0d;
+ foreach (var item in telemetryLastDetectedDates)
+ {
+ onProgressCallback($"Start hanling telemetry: {item.IdTelemetry} from {item.LastDate}", i++ / count);
+ var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
+ if (newOperationsSaub?.Any() == true)
+ {
+ db.SubsystemOperationTimes.AddRange(newOperationsSaub);
+ await db.SaveChangesAsync(token);
+ }
+ var newOperationsSpin = await OperationTimeSpinAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
+ if (newOperationsSpin?.Any() == true)
+ {
+ db.SubsystemOperationTimes.AddRange(newOperationsSpin);
+ await db.SaveChangesAsync(token);
+ }
+ }
+ }
+
+ private static async Task ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
+ {
+ var connection = db.Database.GetDbConnection();
+ if (
+ connection?.State is null ||
+ connection.State == ConnectionState.Broken ||
+ connection.State == ConnectionState.Closed)
+ {
+ await db.Database.OpenConnectionAsync(token);
+ connection = db.Database.GetDbConnection();
+ }
+ using var command = connection.CreateCommand();
+ command.CommandText = query;
+
+ var result = await command.ExecuteReaderAsync(token);
+ return result;
+ }
+
+ private static async Task> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
+ {
+ static bool isSubsytemAkbRotor(short? mode) => mode == 1;
+
+ static bool isSubsytemAkbSlide(short? mode) => mode == 3;
+
+ static bool IsSubsystemMse(short? state) => (state & 1) > 0;
+
+ var query =
+ $"select tt.date, tt.mode, tt.well_depth, tt.mse_state " +
+ $"from ( " +
+ $" select " +
+ $" date, " +
+ $" mode, " +
+ $" mse_state, " +
+ $" well_depth, " +
+ $" lag(mode,1) over (order by date) as mode_lag, " +
+ $" lead(mode,1) over (order by date) as mode_lead " +
+ $" from t_telemetry_data_saub " +
+ $" where id_telemetry = {idTelemetry} and well_depth is not null and well_depth > 0" +
+ $" order by date ) as tt " +
+ $"where (tt.mode_lag is null or (tt.mode != tt.mode_lag and tt.mode_lead != tt.mode_lag)) and tt.date >= '{begin:u}' " +
+ $"order by tt.date;";
+
+ using var result = await ExecuteReaderAsync(db, query, token);
+
+ var subsystemsOperationTimes = new List();
+ var detectorRotor = new SubsystemDetector(idTelemetry, idSubsystemAPDRotor, isSubsytemAkbRotor, IsValid);
+ var detectorSlide = new SubsystemDetector(idTelemetry, idSubsystemAPDSlide, isSubsytemAkbSlide, IsValid);
+ var detectorMse = new SubsystemDetector(idTelemetry, idSubsytemMse, IsSubsystemMse, IsValid);
+
+ while (result.Read())
+ {
+ var mode = result.GetFieldValue(1);
+ var state = result.GetFieldValue(3);
+
+ var isAkbRotorEnable = isSubsytemAkbRotor(mode);
+ var isAkbSlideEnable = isSubsytemAkbSlide(mode);
+ var isMseEnable = IsSubsystemMse(state);
+ var date = result.GetFieldValue(0);
+ var depth = result.GetFieldValue(2);
+
+ if (detectorRotor.TryDetect(mode, date, depth, out var detectedRotor))
+ subsystemsOperationTimes.Add(detectedRotor!);
+
+ if (detectorSlide.TryDetect(mode, date, depth, out var detectedSlide))
+ subsystemsOperationTimes.Add(detectedSlide!);
+
+ if (detectorMse.TryDetect(mode, date, depth, out var detectedMse))
+ subsystemsOperationTimes.Add(detectedMse!);
+ }
+
+ return subsystemsOperationTimes;
+ }
+
+ private static async Task> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
+ {
+ static int? GetSubsytemId(short? mode, int? state)
+ {
+ // При изменении следующего кода сообщи в Vladimir.Sobolev@nedra.digital
+ if (state == 7 && (mode & 2) > 0)
+ return idSubsytemTorqueMaster;// демпфер
+
+ if (state != 0 && state != 5 && state != 6 && state != 7)
+ return idSubsytemSpinMaster;// осцилляция
+
+ return null;
+ }
+
+ var querySpin =
+ $"select " +
+ $" tspin.date, " +
+ $" tspin.mode, " +
+ $" tspin.state " +
+ $"from ( " +
+ $" select " +
+ $" date, " +
+ $" mode, " +
+ $" lag(mode, 1) over (order by date) as mode_lag, " +
+ $" lead(mode, 1) over (order by date) as mode_lead, " +
+ $" state, " +
+ $" lag(state, 1) over (order by date) as state_lag " +
+ $" from t_telemetry_data_spin " +
+ $" where id_telemetry = {idTelemetry} and date >= '{begin:u}'" +
+ $" order by date ) as tspin " +
+ $"where mode_lag is null or state_lag is null or (mode != mode_lag and mode_lead != mode_lag) or state != state_lag " +
+ $"order by date;";
+
+ var rows = new List<(int? IdSubsystem, DateTimeOffset Date)>(32);
+
+ using var resultSpin = await ExecuteReaderAsync(db, querySpin, token);
+ int? idSubsystemLast = null;
+ while (resultSpin.Read())
+ {
+ var mode = resultSpin.GetFieldValue(1);
+ var state = resultSpin.GetFieldValue(2);
+ var idSubsystem = GetSubsytemId(mode, state);
+ if (idSubsystemLast != idSubsystem)
+ {
+ idSubsystemLast = idSubsystem;
+ var date = resultSpin.GetFieldValue(0);
+ rows.Add((idSubsystem, date));
+ }
+ }
+ await resultSpin.DisposeAsync();
+
+ if (rows.Count < 2)
+ return Enumerable.Empty();
+
+ var minSpinDate = rows.Min(i => i.Date);
+ var maxSpinDate = rows.Max(i => i.Date);
+ var depthInterpolation = await GetInterpolation(db, idTelemetry, minSpinDate, maxSpinDate, token);
+
+ if (depthInterpolation is null)
+ return Enumerable.Empty();
+
+ var subsystemsOperationTimes = new List(32);
+
+ for (int i = 1; i < rows.Count; i++)
+ {
+ var r0 = rows[i - 1];
+ var r1 = rows[i];
+ if (r0.IdSubsystem is not null && r0.IdSubsystem != r1.IdSubsystem)
+ {
+ var subsystemOperationTime = new SubsystemOperationTime()
+ {
+ IdTelemetry = idTelemetry,
+ IdSubsystem = r0.IdSubsystem.Value,
+ DateStart = r0.Date,
+ DateEnd = r1.Date,
+ DepthStart = depthInterpolation.GetDepth(r0.Date),
+ DepthEnd = depthInterpolation.GetDepth(r1.Date),
+ };
+
+ if (IsValid(subsystemOperationTime))
+ subsystemsOperationTimes.Add(subsystemOperationTime);
+ }
+ }
+
+ return subsystemsOperationTimes;
+ }
+
+ private static bool IsValid(SubsystemOperationTime item)
+ {
+ var validateCode = GetValidateErrorCode(item);
+ if (validateCode != 0)
+ {
+ var str = System.Text.Json.JsonSerializer.Serialize(item);
+ Trace.TraceWarning($"Wrong({validateCode}) SubsystemOperationTime: {str}");
+ }
+ return validateCode == 0;
+ }
+
+ private static int GetValidateErrorCode(SubsystemOperationTime item)
+ {
+ if (item.DateStart > item.DateEnd)
+ return -1;
+ if ((item.DateEnd - item.DateStart).TotalHours > 48)
+ return -2;
+ if (item.DepthEnd < item.DepthStart)
+ return -3;
+ if (item.DepthEnd - item.DepthStart > 2000d)
+ return -4;
+ if (item.DepthEnd < 0d)
+ return -5;
+ if (item.DepthStart < 0d)
+ return -6;
+ if (item.DepthEnd > 24_0000d)
+ return -7;
+ if (item.DepthStart > 24_0000d)
+ return -8;
+ return 0;
+ }
+
+ private static async Task GetInterpolation(IAsbCloudDbContext db, int idTelemetry, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
+ {
+ var dataDepthFromSaub = await db.TelemetryDataSaub
+ .Where(d => d.IdTelemetry == idTelemetry)
+ .Where(d => d.DateTime >= dateBegin)
+ .Where(d => d.DateTime <= dateEnd)
+ .Where(d => d.WellDepth != null)
+ .Where(d => d.WellDepth > 0)
+ .GroupBy(d => Math.Ceiling(d.WellDepth ?? 0 * 10))
+ .Select(g => new {
+ DateMin = g.Min(d => d.DateTime),
+ DepthMin = g.Min(d => d.WellDepth) ?? 0,
+ })
+ .OrderBy(i => i.DateMin)
+ .ToArrayAsync(token);
+
+ if (!dataDepthFromSaub.Any())
+ return null;
+
+ var depthInterpolation = new DepthInterpolation(dataDepthFromSaub.Select(i => (i.DateMin, i.DepthMin)));
+ return depthInterpolation;
+ }
+}
diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs
index 80456db9..7e4cd8ce 100644
--- a/AsbCloudInfrastructure/Services/WellInfoService.cs
+++ b/AsbCloudInfrastructure/Services/WellInfoService.cs
@@ -18,53 +18,26 @@ using System.Threading.Tasks;
using AsbCloudApp.IntegrationEvents;
using AsbCloudApp.IntegrationEvents.Interfaces;
-namespace AsbCloudInfrastructure.Services
+namespace AsbCloudInfrastructure.Services;
+
+public class WellInfoService
{
- public class WellInfoService
+ public class WorkWellInfoUpdate : Work
{
- class WellMapInfoWithComanies : WellMapInfoDto
+ public WorkWellInfoUpdate()
+ : base("Well statistics update")
{
- public int? IdTelemetry { get; set; }
- public IEnumerable IdsCompanies { get; set; } = null!;
+ Timeout = TimeSpan.FromMinutes(20);
}
- private const string workId = "Well statistics update";
-
- private readonly TelemetryDataCache telemetryDataSaubCache;
- private readonly TelemetryDataCache telemetryDataSpinCache;
- private readonly IWitsRecordRepository witsRecord7Repository;
- private readonly IWitsRecordRepository witsRecord1Repository;
- private readonly IGtrRepository gtrRepository;
- private static IEnumerable WellMapInfo = Enumerable.Empty();
-
- public WellInfoService(
- TelemetryDataCache telemetryDataSaubCache,
- TelemetryDataCache telemetryDataSpinCache,
- IWitsRecordRepository witsRecord7Repository,
- IWitsRecordRepository witsRecord1Repository,
- IGtrRepository gtrRepository)
+ protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token)
{
- this.telemetryDataSaubCache = telemetryDataSaubCache;
- this.telemetryDataSpinCache = telemetryDataSpinCache;
-
- this.witsRecord7Repository = witsRecord7Repository;
- this.witsRecord1Repository = witsRecord1Repository;
- this.gtrRepository = gtrRepository;
- }
-
- public static Work MakeWork() => new Work(workId, WorkAction)
- {
- Timeout = TimeSpan.FromMinutes(20)
- };
-
- private static async Task WorkAction(string workName, IServiceProvider serviceProvider, Action onProgress, CancellationToken token)
- {
- var wellService = serviceProvider.GetRequiredService();
- var operationsStatService = serviceProvider.GetRequiredService();
- var processMapRepository = serviceProvider.GetRequiredService();
- var subsystemOperationTimeService = serviceProvider.GetRequiredService();
- var telemetryDataSaubCache = serviceProvider.GetRequiredService>();
- var messageHub = serviceProvider.GetRequiredService>();
+ var wellService = services.GetRequiredService();
+ var operationsStatService = services.GetRequiredService();
+ var processMapRepository = services.GetRequiredService();
+ var subsystemOperationTimeService = services.GetRequiredService();
+ var telemetryDataSaubCache = services.GetRequiredService>();
+ var messageHub = services.GetRequiredService>();
var wells = await wellService.GetAllAsync(token);
@@ -82,30 +55,30 @@ namespace AsbCloudInfrastructure.Services
});
var operationsStat = await operationsStatService.GetWellsStatAsync(wellsIds, token);
-
+
var subsystemStat = await subsystemOperationTimeService
.GetStatByActiveWells(wellsIds, token);
var count = wells.Count();
- var i = 0;
+ var i = 0d;
WellMapInfo = wells.Select(well => {
var wellMapInfo = well.Adapt();
wellMapInfo.IdState = well.IdState;
- onProgress($"Start updating info by well({well.Id}): {well.Caption}", i++ / count);
+ onProgressCallback($"Start updating info by well({well.Id}): {well.Caption}", i++ / count);
double? currentDepth = null;
TelemetryDataSaubDto? lastSaubTelemetry = null;
-
+
if (well.IdTelemetry.HasValue)
{
wellMapInfo.IdTelemetry = well.IdTelemetry.Value;
lastSaubTelemetry = telemetryDataSaubCache.GetLastOrDefault(well.IdTelemetry.Value);
- if(lastSaubTelemetry is not null)
+ if (lastSaubTelemetry is not null)
{
currentDepth = lastSaubTelemetry.WellDepth;
}
}
- 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);
currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd;
@@ -120,7 +93,7 @@ namespace AsbCloudInfrastructure.Services
{
wellProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
}
- else if(currentDepth.HasValue)
+ else if (currentDepth.HasValue)
{
wellProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value);
}
@@ -130,8 +103,8 @@ namespace AsbCloudInfrastructure.Services
planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd;
wellMapInfo.Section = wellLastFactSection?.Caption;
-
- wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start
+
+ wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start
?? wellOperationsStat?.Total.Plan?.Start;
wellMapInfo.LastPredictOperationDateEnd = wellOperationsStat?.Total.Plan?.End;
@@ -159,7 +132,7 @@ namespace AsbCloudInfrastructure.Services
Plan = wellProcessMap?.Pressure.Plan,
Fact = lastSaubTelemetry?.Pressure
};
-
+
wellMapInfo.PressureSp = lastSaubTelemetry?.PressureSp;
wellMapInfo.WellDepth = new()
@@ -191,51 +164,79 @@ namespace AsbCloudInfrastructure.Services
return wellMapInfo;
}).ToArray();
- var updateWellInfoEventTasks = wellsIds.Select(idWell =>
+ var updateWellInfoEventTasks = wellsIds.Select(idWell =>
messageHub.HandleAsync(new UpdateWellInfoEvent(idWell), token));
-
+
await Task.WhenAll(updateWellInfoEventTasks);
}
+ }
- private WellMapInfoWithTelemetryStat Convert(WellMapInfoWithComanies wellInfo)
+ class WellMapInfoWithComanies : WellMapInfoDto
+ {
+ public int? IdTelemetry { get; set; }
+ public IEnumerable IdsCompanies { get; set; } = null!;
+ }
+
+ private readonly TelemetryDataCache telemetryDataSaubCache;
+ private readonly TelemetryDataCache telemetryDataSpinCache;
+ private readonly IWitsRecordRepository witsRecord7Repository;
+ private readonly IWitsRecordRepository witsRecord1Repository;
+ private readonly IGtrRepository gtrRepository;
+ private static IEnumerable WellMapInfo = Enumerable.Empty();
+
+ public WellInfoService(
+ TelemetryDataCache telemetryDataSaubCache,
+ TelemetryDataCache telemetryDataSpinCache,
+ IWitsRecordRepository witsRecord7Repository,
+ IWitsRecordRepository witsRecord1Repository,
+ IGtrRepository gtrRepository)
+ {
+ this.telemetryDataSaubCache = telemetryDataSaubCache;
+ this.telemetryDataSpinCache = telemetryDataSpinCache;
+
+ this.witsRecord7Repository = witsRecord7Repository;
+ this.witsRecord1Repository = witsRecord1Repository;
+ this.gtrRepository = gtrRepository;
+ }
+
+ private WellMapInfoWithTelemetryStat Convert(WellMapInfoWithComanies wellInfo)
+ {
+ var result = wellInfo.Adapt();
+ if (wellInfo.IdTelemetry.HasValue)
{
- var result = wellInfo.Adapt();
- if (wellInfo.IdTelemetry.HasValue)
- {
- var idTelemetry = wellInfo.IdTelemetry.Value;
- result.LastDataSaub = telemetryDataSaubCache.GetLastOrDefault(idTelemetry);
- result.LastDataSpin = telemetryDataSpinCache.GetLastOrDefault(idTelemetry);
- result.LastDataDdsDate = GetLastOrDefaultDdsTelemetry(idTelemetry);
- result.LastDataGtrDate = gtrRepository.GetLastData(wellInfo.Id)
- .MaxOrDefault(item => item.Date);
- result.LastDataDpcsDate = null;
- result.LastDataDpcsDate = null;
- }
-
- return result;
+ var idTelemetry = wellInfo.IdTelemetry.Value;
+ result.LastDataSaub = telemetryDataSaubCache.GetLastOrDefault(idTelemetry);
+ result.LastDataSpin = telemetryDataSpinCache.GetLastOrDefault(idTelemetry);
+ result.LastDataDdsDate = GetLastOrDefaultDdsTelemetry(idTelemetry);
+ result.LastDataGtrDate = gtrRepository.GetLastData(wellInfo.Id)
+ .MaxOrDefault(item => item.Date);
+ result.LastDataDpcsDate = null;
+ result.LastDataDpcsDate = null;
}
- private DateTime? GetLastOrDefaultDdsTelemetry(int idTelemetry)
- {
- var lastDdsRecord1Date = witsRecord1Repository.GetLastOrDefault(idTelemetry)?.DateTime;
- var lastDdsRecord7Date = witsRecord7Repository.GetLastOrDefault(idTelemetry)?.DateTime;
+ return result;
+ }
- if (lastDdsRecord1Date.HasValue && lastDdsRecord7Date.HasValue)
- if (lastDdsRecord1Date.Value > lastDdsRecord7Date.Value)
- return lastDdsRecord1Date.Value;
- else
- return lastDdsRecord7Date.Value;
+ private DateTime? GetLastOrDefaultDdsTelemetry(int idTelemetry)
+ {
+ var lastDdsRecord1Date = witsRecord1Repository.GetLastOrDefault(idTelemetry)?.DateTime;
+ var lastDdsRecord7Date = witsRecord7Repository.GetLastOrDefault(idTelemetry)?.DateTime;
- return lastDdsRecord1Date ?? lastDdsRecord7Date;
- }
+ if (lastDdsRecord1Date.HasValue && lastDdsRecord7Date.HasValue)
+ if (lastDdsRecord1Date.Value > lastDdsRecord7Date.Value)
+ return lastDdsRecord1Date.Value;
+ else
+ return lastDdsRecord7Date.Value;
- public WellMapInfoWithTelemetryStat? FirstOrDefault(Func predicate)
- {
- var first = WellMapInfo.FirstOrDefault(predicate);
- if (first is WellMapInfoWithComanies wellMapInfoWithComanies)
- return Convert(wellMapInfoWithComanies);
+ return lastDdsRecord1Date ?? lastDdsRecord7Date;
+ }
- return null;
- }
+ public WellMapInfoWithTelemetryStat? FirstOrDefault(Func predicate)
+ {
+ var first = WellMapInfo.FirstOrDefault(predicate);
+ if (first is WellMapInfoWithComanies wellMapInfoWithComanies)
+ return Convert(wellMapInfoWithComanies);
+
+ return null;
}
}
diff --git a/AsbCloudInfrastructure/Services/WorkLimitingParameterCalc.cs b/AsbCloudInfrastructure/Services/WorkLimitingParameterCalc.cs
new file mode 100644
index 00000000..3ab159e0
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/WorkLimitingParameterCalc.cs
@@ -0,0 +1,144 @@
+using AsbCloudDb.Model;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Data.Common;
+using System.Data;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using AsbCloudInfrastructure.Background;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace AsbCloudInfrastructure.Services;
+
+public class WorkLimitingParameterCalc : Work
+{
+ public WorkLimitingParameterCalc()
+ : base("Limiting parameter calc")
+ {
+ Timeout = TimeSpan.FromMinutes(30);
+ }
+
+ protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token)
+ {
+ using var db = services.GetRequiredService();
+ var lastDetectedDates = await db.LimitingParameter
+ .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 telemetryLastDetectedDates = telemetryIds
+ .GroupJoin(lastDetectedDates,
+ t => t,
+ o => o.IdTelemetry,
+ (outer, inner) => new
+ {
+ IdTelemetry = outer,
+ inner.SingleOrDefault()?.LastDate,
+ });
+
+ var count = telemetryLastDetectedDates.Count();
+ var i = 0d;
+ foreach (var item in telemetryLastDetectedDates)
+ {
+ onProgressCallback($"Start hanling telemetry: {item.IdTelemetry} from {item.LastDate}", i++/count);
+ var newLimitingParameters = await GetLimitingParameterAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
+ if (newLimitingParameters?.Any() == true)
+ {
+ db.LimitingParameter.AddRange(newLimitingParameters);
+ await db.SaveChangesAsync(token);
+ }
+ }
+ }
+
+ private static async Task> GetLimitingParameterAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
+ {
+ var query =
+ $"select " +
+ $"limiting_parameters.date, limiting_parameters.id_feed_regulator, limiting_parameters.well_depth " +
+ $"from ( " +
+ $"select " +
+ $"date, id_feed_regulator, well_depth, " +
+ $"lag(id_feed_regulator, 1) over (order by date) as id_feed_regulator_lag, " +
+ $"lead(id_feed_regulator, 1) over (order by date) as id_feed_regulator_lead " +
+ $"from t_telemetry_data_saub " +
+ $"where id_feed_regulator is not null " +
+ $"and id_telemetry = {idTelemetry}" +
+ $"and date >= '{begin:u}'" +
+ $"order by date) as limiting_parameters " +
+ $"where id_feed_regulator_lag is null " +
+ $"or (id_feed_regulator != id_feed_regulator_lag and id_feed_regulator_lead != id_feed_regulator_lag) " +
+ $"order by date;";
+
+ var limitingParameters = new List(32);
+ using (var result = await ExecuteReaderAsync(db, query, token))
+ {
+ LimitingParameter? limitingLast = null;
+ while (result.Read())
+ {
+ var date = result.GetFieldValue(0);
+ var idLimiting = result.GetFieldValue(1);
+ var wellDepth = result.GetFieldValue(2);
+
+ if (limitingLast is null)
+ {
+ limitingLast = new LimitingParameter
+ {
+ DateStart = date,
+ DepthStart = wellDepth,
+ IdFeedRegulator = idLimiting
+ };
+ }
+
+ if (limitingLast.IdFeedRegulator != idLimiting || limitingLast.DepthStart < wellDepth)
+ {
+ limitingParameters.Add(new LimitingParameter {
+ IdTelemetry = idTelemetry,
+ IdFeedRegulator = limitingLast.IdFeedRegulator,
+ DateStart = limitingLast.DateStart,
+ DateEnd = date,
+ DepthStart = limitingLast.DepthStart,
+ DepthEnd = wellDepth
+ });
+
+ limitingLast = new LimitingParameter
+ {
+ DateStart = date,
+ DepthStart = wellDepth,
+ IdFeedRegulator = idLimiting
+ };
+ }
+ }
+ }
+
+ return limitingParameters;
+ }
+
+ private static async Task ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
+ {
+ var connection = db.Database.GetDbConnection();
+ if (
+ connection?.State is null ||
+ connection.State == ConnectionState.Broken ||
+ connection.State == ConnectionState.Closed)
+ {
+ await db.Database.OpenConnectionAsync(token);
+ connection = db.Database.GetDbConnection();
+ }
+ using var command = connection.CreateCommand();
+ command.CommandText = query;
+
+ var result = await command.ExecuteReaderAsync(token);
+ return result;
+ }
+}
diff --git a/AsbCloudInfrastructure/Startup.cs b/AsbCloudInfrastructure/Startup.cs
index 604a4f69..d00de488 100644
--- a/AsbCloudInfrastructure/Startup.cs
+++ b/AsbCloudInfrastructure/Startup.cs
@@ -31,10 +31,10 @@ namespace AsbCloudInfrastructure
_ = provider.GetRequiredService>();
var backgroundWorker = provider.GetRequiredService();
- backgroundWorker.WorkStore.AddPeriodic(WellInfoService.MakeWork(), TimeSpan.FromMinutes(30));
- backgroundWorker.WorkStore.AddPeriodic(OperationDetectionWorkFactory.MakeWork(), TimeSpan.FromMinutes(15));
- backgroundWorker.WorkStore.AddPeriodic(SubsystemOperationTimeCalcWorkFactory.MakeWork(), TimeSpan.FromMinutes(30));
- backgroundWorker.WorkStore.AddPeriodic(LimitingParameterCalcWorkFactory.MakeWork(), TimeSpan.FromMinutes(30));
+ backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(30));
+ backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(15));
+ backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(30));
+ backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(30));
backgroundWorker.WorkStore.AddPeriodic(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
var notificationBackgroundWorker = provider.GetRequiredService();
@@ -55,7 +55,7 @@ namespace AsbCloudInfrastructure
System.Diagnostics.Trace.TraceInformation($"Total memory allocated is {bytesString} bytes. DbContext count is:{AsbCloudDbContext.ReferenceCount}");
return Task.CompletedTask;
};
- var work = new Work("Memory monitoring", workAction);
+ var work = Work.CreateByDelegate("Memory monitoring", workAction);
return work;
}
diff --git a/AsbCloudWebApi.Tests/Middlware/UserConnectionsLimitMiddlwareTest.cs b/AsbCloudWebApi.Tests/Middlware/UserConnectionsLimitMiddlwareTest.cs
index 96556845..b118e179 100644
--- a/AsbCloudWebApi.Tests/Middlware/UserConnectionsLimitMiddlwareTest.cs
+++ b/AsbCloudWebApi.Tests/Middlware/UserConnectionsLimitMiddlwareTest.cs
@@ -1,4 +1,6 @@
-using AsbCloudApp.Data.SAUB;
+using AsbCloudApp.Data;
+using AsbCloudApp.Data.SAUB;
+using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
@@ -35,12 +37,22 @@ namespace AsbCloudWebApi.Tests.Middlware
public class TelemetryDataSaubService : ITelemetryDataSaubService
{
- public async Task?> GetAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default)
+ public async Task> GetAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default)
{
await Task.Delay(1000, token);
return Enumerable.Empty();
}
+ public Task> GetAsync(int idWell, TelemetryDataRequest request, CancellationToken token)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task GetRangeAsync(int idWell, DateTimeOffset start, DateTimeOffset end, CancellationToken token)
+ {
+ throw new NotImplementedException();
+ }
+
public Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token) => throw new NotImplementedException();
public Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
diff --git a/AsbCloudWebApi/Controllers/BackgroundWork.cs b/AsbCloudWebApi/Controllers/BackgroundWork.cs
new file mode 100644
index 00000000..316d796e
--- /dev/null
+++ b/AsbCloudWebApi/Controllers/BackgroundWork.cs
@@ -0,0 +1,34 @@
+using AsbCloudApp.Data;
+using AsbCloudInfrastructure.Background;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Linq;
+
+namespace AsbCloudWebApi.Controllers
+{
+ [Route("api/[controller]")]
+ [Authorize]
+ [ApiController]
+ public class BackgroundWork : ControllerBase
+ {
+ private readonly BackgroundWorker backgroundWorker;
+
+ public BackgroundWork(BackgroundWorker backgroundWorker)
+ {
+ this.backgroundWorker = backgroundWorker;
+ }
+
+ [HttpGet]
+ //[ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
+ public IActionResult GetAll()
+ {
+ var result = new {
+ CurrentWork = (BackgroundWorkDto?)backgroundWorker.CurrentWork,
+ RunOnceQueue = backgroundWorker.WorkStore.RunOnceQueue.Select(work => (BackgroundWorkDto)work),
+ Periodics = backgroundWorker.WorkStore.Periodics.Select(work => (BackgroundWorkDto)work.Work),
+ Felled = backgroundWorker.WorkStore.Felled.Select(work => (BackgroundWorkDto)work),
+ };
+ return Ok(result);
+ }
+ }
+}
diff --git a/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs b/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs
index 143055e5..962e5e0f 100644
--- a/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs
+++ b/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs
@@ -33,7 +33,7 @@ public class SignalRNotificationTransportService : INotificationTransportService
return Task.CompletedTask;
var workAction = MakeSignalRSendWorkAction(notifications);
- var work = new Work(workId, workAction);
+ var work = Work.CreateByDelegate(workId, workAction);
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
return Task.CompletedTask;
diff --git a/ConsoleApp1/DebugWellOperationsStatService.cs b/ConsoleApp1/DebugWellOperationsStatService.cs
deleted file mode 100644
index acb6452c..00000000
--- a/ConsoleApp1/DebugWellOperationsStatService.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using AsbCloudApp.Data;
-using System;
-using System.Collections.Generic;
-
-namespace ConsoleApp1
-{
- public static class DebugWellOperationsStatService
- {
- public static void Main(/*string[] args*/)
- {
- //var options = new DbContextOptionsBuilder()
- // .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
- // .Options;
- //using var db = new AsbCloudDbContext(options);
- //var cacheDb = new CacheDb();
- //var telemetryService = new TelemetryService(db, new TelemetryTracker(cacheDb), cacheDb);
- //var wellService = new WellService(db, telemetryService, cacheDb);
- //var wellOptsStat = new OperationsStatService(db, cacheDb, wellService);
- //var tvd = wellOptsStat.GetTvdAsync(1, default).Result;
- //Print(tvd);
- }
-
- private static void Print(IEnumerable> tvd)
- {
- Console.WriteLine("|\tplan\t|\tfact\t|\tprog\t|");
- Console.WriteLine("|:-------------:|:-------------:|:-------------:|");
- foreach (var item in tvd)
- Print(item);
- }
-
- private static void Print(PlanFactPredictBase item)
- {
- static string GetText(WellOperationDto item)
- => (item is null)
- ? " --------- "
- : $"{item.IdCategory} d:{item.DepthStart} ";
- Console.WriteLine($"|\t{GetText(item.Plan)}\t|\t{GetText(item.Fact)}\t|\t{GetText(item.Predict)}\t|");
- }
- }
-}