#7576630 refactor telemetryService.

Добавить nullable.
Заменить зависимость от CacheTable/CacheDb.
Удалить не используемые методы.
This commit is contained in:
ngfrolov 2022-10-31 15:21:53 +05:00
parent c54f88ae80
commit e185d8b82a
5 changed files with 76 additions and 149 deletions

View File

@ -1,12 +1,12 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using System; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
#nullable enable
/// <summary> /// <summary>
/// Сервис телеметрии /// Сервис телеметрии
/// </summary> /// </summary>
@ -43,21 +43,12 @@ namespace AsbCloudApp.Services
/// <returns></returns> /// <returns></returns>
SimpleTimezoneDto GetTimezone(int idTelemetry); SimpleTimezoneDto GetTimezone(int idTelemetry);
// TODO: вероятно лишнее
/// <summary>
/// Список передающих в данный момент телеметрий
/// </summary>
/// <returns></returns>
IEnumerable<TelemetryDto> GetTransmittingTelemetries();
// TODO: вероятно лишнее
/// <summary> /// <summary>
/// Получить дату получения последних данных /// Получить дату получения последних данных
/// </summary> /// </summary>
/// <param name="idTelemetry"></param> /// <param name="idTelemetry"></param>
/// <param name="useUtc"></param>
/// <returns></returns> /// <returns></returns>
DateTime GetLastTelemetryDate(int idTelemetry, bool useUtc = false); DateTime GetLastTelemetryDate(int idTelemetry);
/// <summary> /// <summary>
/// получить idTelemetry по IdWell /// получить idTelemetry по IdWell
@ -82,16 +73,6 @@ namespace AsbCloudApp.Services
/// <returns></returns> /// <returns></returns>
Task UpdateInfoAsync(string uid, TelemetryInfoDto info, CancellationToken token); Task UpdateInfoAsync(string uid, TelemetryInfoDto info, CancellationToken token);
// TODO: вероятно лишнее
/// <summary>
/// обновить данные о временной зоне (используется панелью)
/// </summary>
/// <param name="uid"></param>
/// <param name="telemetryTimeZoneInfo"></param>
/// <param name="token"></param>
/// <returns></returns>
Task UpdateTimezoneAsync(string uid, SimpleTimezoneDto telemetryTimeZoneInfo, CancellationToken token);
/// <summary> /// <summary>
/// Слить данные телеметрии в одну /// Слить данные телеметрии в одну
/// </summary> /// </summary>
@ -100,13 +81,7 @@ namespace AsbCloudApp.Services
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> MergeAsync(int from, int to, CancellationToken token); Task<int> MergeAsync(int from, int to, CancellationToken token);
// TODO: вероятно лишнее
/// <summary>
/// сохранить данные о запросе
/// </summary>
/// <param name="uid"></param>
/// <param name="remoteDate"></param>
void SaveRequestDate(string uid, DateTimeOffset remoteDate);
} }
#nullable disable
} }

View File

@ -141,10 +141,6 @@ namespace AsbCloudInfrastructure.Services.SAUB
var telemetryId = telemetryService.GetOrCreateTelemetryIdByUid(uid); var telemetryId = telemetryService.GetOrCreateTelemetryIdByUid(uid);
var timezone = telemetryService.GetTimezone(telemetryId); var timezone = telemetryService.GetTimezone(telemetryId);
var maxDateDto = dtos.Max(m => m.Date);
var maxDateUtc = maxDateDto.ToUtcDateTimeOffset(timezone.Hours);
telemetryService.SaveRequestDate(uid, maxDateDto);
foreach (var dto in dtos) foreach (var dto in dtos)
{ {
var entity = dto.Adapt<TelemetryMessage>(); var entity = dto.Adapt<TelemetryMessage>();

View File

@ -14,13 +14,11 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
public abstract class TelemetryDataBaseService<TDto, TModel> : ITelemetryDataService<TDto> public abstract class TelemetryDataBaseService<TDto, TModel> : ITelemetryDataService<TDto>
where TDto : AsbCloudApp.Data.ITelemetryData where TDto : AsbCloudApp.Data.ITelemetryData
where TModel : class, AsbCloudDb.Model.ITelemetryData where TModel : class, ITelemetryData
{ {
protected readonly IAsbCloudDbContext db; protected readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
protected readonly CacheTable<Telemetry> cacheTelemetry;
protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers; protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers;
protected readonly CacheTable<Well> cacheWells;
public TelemetryDataBaseService( public TelemetryDataBaseService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
@ -29,9 +27,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
this.db = db; this.db = db;
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
cacheTelemetryUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db); cacheTelemetryUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db);
cacheWells = cacheDb.GetCachedTable<Well>((AsbCloudDbContext)db);
} }
public virtual async Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default) public virtual async Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default)
@ -65,7 +61,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
}); });
var entityMaxDate = entities.Max(e => e.DateTime); var entityMaxDate = entities.Max(e => e.DateTime);
telemetryService.SaveRequestDate(uid, entityMaxDate); telemetryService.TelemetryTracker.SaveRequestDate(uid, entityMaxDate);
var dbset = db.Set<TModel>(); var dbset = db.Set<TModel>();
var stopwatch = Stopwatch.StartNew(); var stopwatch = Stopwatch.StartNew();
@ -91,11 +87,9 @@ namespace AsbCloudInfrastructure.Services.SAUB
DateTime dateBegin = default, double intervalSec = 600d, DateTime dateBegin = default, double intervalSec = 600d,
int approxPointsCount = 1024, CancellationToken token = default) int approxPointsCount = 1024, CancellationToken token = default)
{ {
var well = cacheWells.FirstOrDefault(w => w.Id == idWell); var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell) ?? -1;
if (well?.IdTelemetry is null) if (idTelemetry == -1)
return default; return null;
var idTelemetry = well?.IdTelemetry ?? default;
var timezone = telemetryService.GetTimezone(idTelemetry); var timezone = telemetryService.GetTimezone(idTelemetry);
@ -103,7 +97,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
DateTimeOffset dateBeginUtc; DateTimeOffset dateBeginUtc;
if (dateBegin == default) if (dateBegin == default)
{ {
dateBeginUtc = telemetryService.GetLastTelemetryDate(idTelemetry, true); dateBeginUtc = telemetryService.GetLastTelemetryDate(idTelemetry)
.ToUtcDateTimeOffset(timezone.Hours);
if (dateBeginUtc != default) if (dateBeginUtc != default)
dateBeginUtc = dateBeginUtc.AddSeconds(-intervalSec); dateBeginUtc = dateBeginUtc.AddSeconds(-intervalSec);
} }
@ -153,24 +148,5 @@ namespace AsbCloudInfrastructure.Services.SAUB
public abstract TModel Convert(TDto src, double timezoneOffset); public abstract TModel Convert(TDto src, double timezoneOffset);
private static double AssumeTimezoneOffset(DateTime nearToCurrentDate)
{
var offset = 5d;
if (nearToCurrentDate.Kind == DateTimeKind.Unspecified)
{
var now = DateTime.UtcNow;
var minutes = 60 * (now.Hour - nearToCurrentDate.Hour) + now.Minute - nearToCurrentDate.Minute;
var minutesPositive = (1440_0000 + minutes) % 1440; //60*24
var halfsHours = Math.Round(1d * minutesPositive / 30d); // quarters are ignored
var hours = halfsHours / 2;
offset = hours < 12 ? hours : 24 - hours;
}
if (nearToCurrentDate.Kind == DateTimeKind.Local)
offset = TimeZoneInfo.Local.BaseUtcOffset.TotalHours;
return offset;
}
} }
} }

View File

@ -3,7 +3,7 @@ using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb; using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache; using AsbCloudInfrastructure.EfCache;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
@ -14,10 +14,12 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.SAUB namespace AsbCloudInfrastructure.Services.SAUB
{ {
#nullable enable
public class TelemetryService : ITelemetryService public class TelemetryService : ITelemetryService
{ {
private readonly CacheTable<Telemetry> cacheTelemetry; private const string telemetryCacheTag = "telemetryCache";
private readonly CacheTable<Well> cacheWells;//TODO: use wellService instead of this private static readonly TimeSpan telemetryCacheObsolescence = TimeSpan.FromMinutes(5);
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly ITelemetryTracker telemetryTracker; private readonly ITelemetryTracker telemetryTracker;
private readonly ITimezoneService timezoneService; private readonly ITimezoneService timezoneService;
@ -28,59 +30,42 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryService( public TelemetryService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryTracker telemetryTracker, ITelemetryTracker telemetryTracker,
ITimezoneService timezoneService, ITimezoneService timezoneService)
CacheDb cacheDb)
{ {
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
cacheWells = cacheDb.GetCachedTable<Well>(
(AsbCloudDbContext)db,
$"{nameof(Well.Cluster)}.{nameof(Cluster.Deposit)}",
nameof(Well.Telemetry),
$"{nameof(Well.RelationCompaniesWells)}.{nameof(RelationCompanyWell.Company)}",
nameof(Well.WellType));
this.db = db; this.db = db;
this.telemetryTracker = telemetryTracker; this.telemetryTracker = telemetryTracker;
this.timezoneService = timezoneService; this.timezoneService = timezoneService;
} }
public IEnumerable<TelemetryDto> GetTransmittingTelemetries() private Dictionary<int, Telemetry> GetTelemetryCache()
{ {
var telemetryDtos = new List<TelemetryDto>(); var cache = db.Telemetries
var activeTelemetriesUids = telemetryTracker.GetTransmittingTelemetriesUids(); .Include(t => t.Well)
if (!activeTelemetriesUids.Any()) .FromCacheDictionary(telemetryCacheTag, telemetryCacheObsolescence, t => t.Id);
return telemetryDtos; return cache;
var telemetries = cacheTelemetry
.Where(t => activeTelemetriesUids.Contains(t.RemoteUid));
telemetryDtos = telemetries.Adapt<IEnumerable<TelemetryDto>>().ToList();
return telemetryDtos;
} }
public void SaveRequestDate(string uid, DateTimeOffset remoteDate) => private void DropTelemetryCache()
telemetryTracker.SaveRequestDate(uid, remoteDate);
public DateTime GetLastTelemetryDate(int idTelemetry, bool useUtc = false)
{ {
var lastTelemetryDate = DateTimeOffset.MinValue; db.Telemetries.DropCacheDictionary(telemetryCacheTag);
var telemetry = cacheTelemetry.FirstOrDefault(t => t.Id == idTelemetry); }
public DateTime GetLastTelemetryDate(int idTelemetry)
{
var telemetry = GetTelemetryCache().GetValueOrDefault(idTelemetry);
if (telemetry is null) if (telemetry is null)
throw new Exception($"Telemetry id:{idTelemetry} does not exist"); throw new Exception($"Telemetry id:{idTelemetry} does not exist");
var uid = telemetry.RemoteUid; var uid = telemetry.RemoteUid;
var timzone = GetTimezone(idTelemetry); var timzone = GetTimezone(idTelemetry);
var lastTelemetryDate = telemetryTracker.GetLastTelemetryDateByUid(uid);
lastTelemetryDate = telemetryTracker.GetLastTelemetryDateByUid(uid);
if (useUtc)
return lastTelemetryDate.UtcDateTime;
return lastTelemetryDate.ToRemoteDateTime(timzone.Hours); return lastTelemetryDate.ToRemoteDateTime(timzone.Hours);
} }
public DatesRangeDto GetDatesRange(int idTelemetry) public DatesRangeDto GetDatesRange(int idTelemetry)
{ {
var telemetry = cacheTelemetry.FirstOrDefault(t => t.Id == idTelemetry); var telemetry = GetTelemetryCache().GetValueOrDefault(idTelemetry);
if (telemetry is null) if (telemetry is null)
throw new Exception($"Telemetry id:{idTelemetry} does not exist"); throw new Exception($"Telemetry id:{idTelemetry} does not exist");
@ -115,13 +100,14 @@ namespace AsbCloudInfrastructure.Services.SAUB
TimezoneId = info.TimeZoneId TimezoneId = info.TimeZoneId
}; };
await cacheTelemetry.UpsertAsync(telemetry, token) db.Telemetries.Upsert(telemetry);
.ConfigureAwait(false); await db.SaveChangesAsync(token);
DropTelemetryCache();
} }
public SimpleTimezoneDto GetTimezone(int idTelemetry) public SimpleTimezoneDto GetTimezone(int idTelemetry)
{ {
var telemetry = cacheTelemetry.FirstOrDefault(t => t.Id == idTelemetry); var telemetry = GetTelemetryCache().GetValueOrDefault(idTelemetry);
if (telemetry is null) if (telemetry is null)
throw new Exception($"Telemetry id: {idTelemetry} does not exist."); throw new Exception($"Telemetry id: {idTelemetry} does not exist.");
@ -137,58 +123,65 @@ namespace AsbCloudInfrastructure.Services.SAUB
IsOverride = false, IsOverride = false,
TimezoneId = telemetry.Info.TimeZoneId, TimezoneId = telemetry.Info.TimeZoneId,
}; };
cacheTelemetry.Upsert(telemetry); db.Telemetries.Upsert(telemetry);
db.SaveChanges();
DropTelemetryCache();
return telemetry.TimeZone.Adapt<SimpleTimezoneDto>(); return telemetry.TimeZone.Adapt<SimpleTimezoneDto>();
} }
if (telemetry.Well?.Timezone is not null) if (telemetry.Well?.Timezone is not null)
{ {
telemetry.TimeZone = telemetry.Well.Timezone; telemetry.TimeZone = telemetry.Well.Timezone;
cacheTelemetry.Upsert(telemetry); db.Telemetries.Upsert(telemetry);
db.SaveChanges();
DropTelemetryCache();
return telemetry.TimeZone.Adapt<SimpleTimezoneDto>(); return telemetry.TimeZone.Adapt<SimpleTimezoneDto>();
} }
throw new Exception($"Telemetry id: {idTelemetry} can't find timezone."); throw new Exception($"Telemetry id: {idTelemetry} can't find timezone.");
} }
public async Task UpdateTimezoneAsync(string uid, SimpleTimezoneDto timeone,
CancellationToken token)
{
var telemetry = GetOrCreateTelemetryByUid(uid);
var newTelemetryTimeZone = timeone.Adapt<SimpleTimezone>();
if (newTelemetryTimeZone?.Equals(telemetry.TimeZone) == true)
return;
await cacheTelemetry.UpsertAsync(telemetry, token)
.ConfigureAwait(false);
}
public int? GetIdTelemetryByIdWell(int idWell) public int? GetIdTelemetryByIdWell(int idWell)
{ {
var well = cacheWells.FirstOrDefault(w => w.Id == idWell); var telemetry = GetTelemetryCache()
return well?.IdTelemetry; .FirstOrDefault(t => t.Value.Well?.Id == idWell).Value;
return telemetry?.Id;
} }
private Well GetWellByTelemetryUid(string uid) private Well? GetWellByTelemetryUid(string uid)
{ {
var tele = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid); var telemetry = GetOrDefaultTelemetryByUid(uid);
if (tele is null) return telemetry?.Well;
return null; }
var well = cacheWells.FirstOrDefault(w => w?.IdTelemetry == tele.Id); private Telemetry? GetOrDefaultTelemetryByUid(string uid)
return well; {
var telemetry = GetTelemetryCache().FirstOrDefault(kv => kv.Value.RemoteUid == uid).Value;
return telemetry;
} }
private Telemetry GetOrCreateTelemetryByUid(string uid) private Telemetry GetOrCreateTelemetryByUid(string uid)
=> cacheTelemetry.GetOrCreate(t => t.RemoteUid == uid, () => new Telemetry {
var telemetry = GetOrDefaultTelemetryByUid(uid);
if (telemetry is null)
{ {
RemoteUid = uid, var newTelemetry = new Telemetry
TimeZone = new SimpleTimezone
{ {
Hours = 5, RemoteUid = uid,
IsOverride = false, TimeZone = new SimpleTimezone
TimezoneId = "default", {
} Hours = 5,
}); IsOverride = false,
TimezoneId = "default",
}
};
var entry = db.Telemetries.Add(newTelemetry);
db.SaveChanges();
DropTelemetryCache();
return entry.Entity;
}
return telemetry;
}
public async Task<int> MergeAsync(int from, int to, CancellationToken token) public async Task<int> MergeAsync(int from, int to, CancellationToken token)
{ {
@ -229,12 +222,15 @@ namespace AsbCloudInfrastructure.Services.SAUB
stopwath.Stop(); stopwath.Stop();
Console.WriteLine($"Successfully committed in {1d * stopwath.ElapsedMilliseconds / 1000d: #0.00} sec. Affected {affected} rows."); Console.WriteLine($"Successfully committed in {1d * stopwath.ElapsedMilliseconds / 1000d: #0.00} sec. Affected {affected} rows.");
DropTelemetryCache();
return affected; return affected;
} }
catch (Exception ex) catch (Exception ex)
{ {
System.Diagnostics.Trace.WriteLine($"Merge() Fail. Rollback. Reason is:{ex.Message}"); System.Diagnostics.Trace.WriteLine($"Merge() Fail. Rollback. Reason is:{ex.Message}");
await transaction.RollbackAsync(token).ConfigureAwait(false); #pragma warning disable CA2016 // Перенаправьте параметр "CancellationToken" в методы
await transaction.RollbackAsync();
#pragma warning restore CA2016 // Перенаправьте параметр "CancellationToken" в методы
return -1; return -1;
} }
} }
@ -352,4 +348,5 @@ namespace AsbCloudInfrastructure.Services.SAUB
return affected; return affected;
} }
} }
#nullable disable
} }

View File

@ -54,23 +54,6 @@ namespace AsbCloudWebApi.Controllers.SAUB
return Ok(); return Ok();
} }
/// <summary>
/// Обновляет часовой пояс скважины
/// </summary>
/// <param name="uid">Уникальный идентификатор отправителя</param>
/// <param name="timezone">Информация о часовом поясе</param>
/// <param name="token">Токен отмены задачи</param>
/// <returns></returns>
[HttpPost]
[Route("{uid}/timezone")]
public async Task<IActionResult> UpdateTimeZoneAsync(string uid, SimpleTimezoneDto timezone,
CancellationToken token)
{
await telemetryService.UpdateTimezoneAsync(uid, timezone, token)
.ConfigureAwait(false);
return Ok();
}
/// <summary> /// <summary>
/// Принимает список новых сообщений от телеметрии /// Принимает список новых сообщений от телеметрии
/// </summary> /// </summary>