diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs
index ecb11262..f2ced40a 100644
--- a/PARR.API/Contracts/V1/ApiRoutes.cs
+++ b/PARR.API/Contracts/V1/ApiRoutes.cs
@@ -49,20 +49,7 @@
public const string GetNextRun = Base + "/tests/next-run";
- public const string GetNextScheduleDate = Base + "/tests/next-schedule-date/" + paramApplicationInWorkId + "/" + paramDate;
-
- public const string GetNextSchedule = Base + "/tests/next-schedule/" + paramApplicationInWorkId + "/" + paramDate;
-
public const string CreateCache = Base + "/tests/cache/";
-
- public const string IsWorkDay = Base + "/tests/is-work-day/";
-
- public const string TestHandler = Base + "/tests/test/";
-
- public const string GetWorkDay = Base + "/tests/get-work-day/{date}";
-
- public const string paramDate = "{lastRunDate}";
- public const string paramApplicationInWorkId = "{applicationInWorkId}";
}
public static class Template
diff --git a/PARR.API/Controllers/V1/TestController.cs b/PARR.API/Controllers/V1/TestController.cs
index da19f183..e76fa8c6 100644
--- a/PARR.API/Controllers/V1/TestController.cs
+++ b/PARR.API/Controllers/V1/TestController.cs
@@ -1,16 +1,12 @@
-using AutoMapper;
-using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base;
using PARR.API.Services.Interfaces;
using PARR.DAL.Cache.Services.Base;
-using PARR.DAL.DomainServices.UnitFilterService;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces;
-using PARR.DAL.Services.Interfaces.Job;
-using PARR.DAL.Services.Interfaces.Unit;
namespace PARR.API.Controllers.V1
@@ -19,43 +15,19 @@ namespace PARR.API.Controllers.V1
public class TestController : BaseApiController
{
private readonly IClientService clientService;
- //private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly IRedisCacheService redisCacheService;
- private readonly IWeekendDayService weekendDayService;
- private readonly IUnitService unitService;
- private readonly IFieldFilterService fieldFilterService;
- private readonly IJobService jobService;
- private readonly IJobUnitFilterService jobUnitFilterService;
- private readonly IUnitFilterService unitFilterService;
- private readonly IMapper mapper;
private readonly INextRunService nextRunService;
private readonly ITemplateService templateService;
public TestController(
IClientService clientService,
- //IEsppScheduleTransformService esppScheduleTransformService,
IRedisCacheService redisCacheService,
- IWeekendDayService weekendDayService,
- IUnitService unitService,
- IFieldFilterService fieldFilterService,
- IJobService jobService,
- IJobUnitFilterService jobUnitFilterService,
- IUnitFilterService unitFilterService,
- IMapper mapper,
INextRunService nextRunService,
ITemplateService templateService
)
{
this.clientService = clientService;
- //this.esppScheduleTransformService = esppScheduleTransformService;
this.redisCacheService = redisCacheService;
- this.weekendDayService = weekendDayService;
- this.unitService = unitService;
- this.fieldFilterService = fieldFilterService;
- this.jobService = jobService;
- this.jobUnitFilterService = jobUnitFilterService;
- this.unitFilterService = unitFilterService;
- this.mapper = mapper;
this.nextRunService = nextRunService;
this.templateService = templateService;
}
@@ -92,124 +64,47 @@ namespace PARR.API.Controllers.V1
}
- /////
- ///// Получить следующую дату запуска
- /////
- /////
- /////
- /////
- //[HttpGet(ApiRoutes.Test.GetNextScheduleDate)]
- //public async Task GetNextScheduleDate([FromRoute] Guid applicationInWorkId, [FromRoute] DateTimeOffset lastRunDate)
- //{
- // var result = await esppScheduleTransformService.GetNextDateAsync(applicationInWorkId, lastRunDate);
- // return Ok(result);
- //}
-
/////
- ///// Получить следующее расписание
+ ///// Записать в кэш
/////
- /////
- /////
+ /////
/////
- //[HttpGet(ApiRoutes.Test.GetNextSchedule)]
- //public async Task GetNextSchedule([FromRoute] Guid applicationInWorkId, [FromRoute] DateTimeOffset lastRunDate)
+ //[HttpPost(ApiRoutes.Test.CreateCache)]
+ //public async Task CreateCache()
//{
- // var result = await esppScheduleTransformService.GetNextScheduleAsync(applicationInWorkId, lastRunDate);
- // return Ok(result);
+ // var hashKey = redisCacheService.GetKey(new[] { "test", "mxa" });
+ // var ttl = TimeSpan.FromMinutes(10);
+
+ // await redisCacheService.SetHashFieldAsync(hashKey, "t1", "val1", ttl);
+ // await redisCacheService.SetHashFieldAsync(hashKey, "t2", "val2");
+ // await redisCacheService.SetHashFieldAsync(hashKey, "t3", "val3");
+
+ // var length = await redisCacheService.GetHashLengthAsync(hashKey);
+
+ // var get = await redisCacheService.GetHashFieldAsync(hashKey, "t1");
+
+ // var getAll = await redisCacheService.GetAllHashFieldsAsync(hashKey);
+
+ // await redisCacheService.DeleteHashFieldAsync(hashKey, "t1");
+ // var getT1 = await redisCacheService.GetHashFieldAsync(hashKey, "t1");
+
+ // var exist = await redisCacheService.HashFieldExistsAsync(hashKey, "t2");
+
+ // await redisCacheService.DeleteHashAsync(hashKey);
+ // var getT_1 = await redisCacheService.GetHashFieldAsync(hashKey, "t1");
+
+ // await redisCacheService.SetHashTtlAsync(hashKey, ttl);
+
+ // return Ok();
//}
- ///
- /// Записать в кэш и получить обратно значение из кэша
- ///
- ///
- ///
- [HttpPost(ApiRoutes.Test.CreateCache)]
- public async Task CreateCache([FromBody] CaheRequestTest request)
- {
- await redisCacheService.SetCachedDataAsync(request.Key, request, TimeSpan.FromMinutes(1));
-
- var fromCache = await redisCacheService.GetCachedDataAsync(request.Key);
-
- return Ok(new { fromCache });
- }
- ///
- /// Проверка, это рабочий день?
- ///
- ///
- ///
- [HttpGet(ApiRoutes.Test.IsWorkDay)]
- public async Task IsWorkDay([FromQuery] DateOnly date)
- {
- return Ok(await weekendDayService.IsWorkDayAsync(date, true));
- }
- ///
- /// Тестовый метод
- ///
- ///
- [HttpGet(ApiRoutes.Test.TestHandler)]
- public async Task Test()
- {
- //var job = new Job
- //{
- // Id = Guid.NewGuid(),
- // Name = "ВИ-VMWARE ТО-1 Мониторинг и анализ работы виртуальной инфраструктуры",
- // DateCreated = DateTimeOffset.Now,
- // TemplateNameMask = "ЭИТИ_%РГ%_%ТНК%_%ЭК%",
- // TnkId = Guid.Parse("9b7e0251-cb13-427c-ac71-16baa2a111dd")
- //};
- //var jobDetails = new JobDetails {
- // Id = Guid.NewGuid(),
- // UnitFilter = "ВРТ-VMWARE-*",
- // JobId = job.Id,
- // ShortDescription = "Мониторинг и анализ работы виртуальной инфраструктуры",
- // FullDescription = "Проверка журналов (лог-файла) событий (warning, alarm) объектов виртуальной инфраструктуры (ВМ, хост, кластер, датацентр, virtual center и др.)",
- // Solution = "Работы проведены",
- // Duration = "7 00:00:00",
- // ReferenceDate = new DateTimeOffset(2026,01,01,00,00,00,new TimeSpan(0))
- //};
-
- //var fieldFilter = new FieldFilter
- //{
- // Id = Guid.NewGuid(),
- // JobDetailsId = jobDetails.Id,
- // FieldId = Guid.Parse("08b42860-09a7-4a1f-aa4f-0290e86df884"),
- // ValueMask = "виртуальный комплекс"
- //};
- ////await jobService.CreateAsync(job);
- ////await jobService.CommitAsync();
- //if (await jobService.CreateAsync(job))
- // if (await jobDetailsService.CreateAsync(jobDetails))
- // if (await fieldFilterService.CreateAsync(fieldFilter))
- // await jobService.CommitAsync();
- //var unit = await unitService.Get().Include(t => t.Parents).Include(t => t.Childs).FirstOrDefaultAsync(t => t.Id == Guid.Parse("01fda0bd-3423-4b12-965b-2947153d1d87"));
-
- //var parent = unit?.Parents;
- //var child = unit?.Childs;
-
- return Ok();
- }
-
-
- //[HttpGet(ApiRoutes.Test.GetWorkDay)]
- //public async Task GetWorkDay([FromRoute] DateTimeOffset date)
- //{
- // var result = await esppScheduleTransformService.GetWorkDayAsync(date);
-
- // return Ok(result);
- //}
}
- public class CaheRequestTest
- {
- public required string Key { get; set; }
-
- public required string Value { get; set; }
- }
}
diff --git a/PARR.DAL/Cache/Services/Base/IRedisCacheService.cs b/PARR.DAL/Cache/Services/Base/IRedisCacheService.cs
index 881fdf8a..01a48bb8 100644
--- a/PARR.DAL/Cache/Services/Base/IRedisCacheService.cs
+++ b/PARR.DAL/Cache/Services/Base/IRedisCacheService.cs
@@ -57,5 +57,75 @@
///
///
string GetKey(string[] keyParts, bool isUseHash = false);
+
+ #region Работа с Hash
+
+ ///
+ /// Изменить одно поле в Hash
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Если указано, обновится у всего Hash. Если не указано и hash не существовал, создастся Hash с бесокнечным ttl
+ ///
+ Task SetHashFieldAsync(string hashKey, string field, T value, TimeSpan? ttl = null);
+
+ ///
+ /// Получить значение поля из Hash
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetHashFieldAsync(string hashKey, string field);
+
+ ///
+ /// Получить все значения из Hash
+ ///
+ ///
+ ///
+ ///
+ Task> GetAllHashFieldsAsync(string hashKey);
+
+ ///
+ /// Удалить одну запись из Hash
+ ///
+ ///
+ ///
+ ///
+ Task DeleteHashFieldAsync(string hashKey, string field);
+
+ ///
+ /// Есть ли запись в Hash
+ ///
+ ///
+ ///
+ ///
+ Task HashFieldExistsAsync(string hashKey, string field);
+
+ ///
+ /// Удалить весь Hash
+ ///
+ ///
+ ///
+ Task DeleteHashAsync(string hashKey);
+
+ ///
+ /// Получить количество записей в Hash
+ ///
+ ///
+ ///
+ Task GetHashLengthAsync(string hashKey);
+
+ ///
+ /// Установить TTL для Hash
+ ///
+ ///
+ ///
+ ///
+ Task SetHashTtlAsync(string hashKey, TimeSpan ttl);
+
+ #endregion
}
}
diff --git a/PARR.DAL/Cache/Services/Base/RedisCacheService.cs b/PARR.DAL/Cache/Services/Base/RedisCacheService.cs
index 38c902be..bb7fa130 100644
--- a/PARR.DAL/Cache/Services/Base/RedisCacheService.cs
+++ b/PARR.DAL/Cache/Services/Base/RedisCacheService.cs
@@ -1,17 +1,26 @@
using Microsoft.Extensions.Caching.Distributed;
+using StackExchange.Redis;
using System.Text.Json;
+using static System.Runtime.InteropServices.JavaScript.JSType;
namespace PARR.DAL.Cache.Services.Base
{
internal class RedisCacheService : IRedisCacheService
{
private readonly IDistributedCache cache;
+ private readonly IDatabase redis;
- public RedisCacheService(IDistributedCache cache)
+ public RedisCacheService(
+ IDistributedCache cache,
+ IConnectionMultiplexer connectionMultiplexer
+ )
{
this.cache = cache;
+ this.redis = connectionMultiplexer.GetDatabase();
}
+ #region Распределенный кэш IDistributedCache
+
public async Task GetCachedDataAsync(string key)
{
var jsonData = await cache.GetStringAsync(key);
@@ -69,6 +78,85 @@ namespace PARR.DAL.Cache.Services.Base
cache.Remove(key);
}
+ #endregion
+
+ #region Нативные операции Redis, Redis Hash
+
+ public async Task SetHashFieldAsync(string hashKey, string field, T value, TimeSpan? ttl = null)
+ {
+ // меняет одно поле в Hash
+
+ var jsonData = JsonSerializer.Serialize(value);
+
+ // true - поля не было, создалось новое. false - поле было, обновили значение
+ var result = await redis.HashSetAsync(hashKey, field, jsonData);
+
+ // если указан ttl, обновим для всего Hash
+ // если не указан и ранее был создан hashKey, оставит его ttl; а если hashKey не было, то создаст его БЕССРОЧНЫМ!!!
+ if (ttl.HasValue)
+ await SetHashTtlAsync(hashKey, ttl.Value);
+ }
+
+ public async Task GetHashFieldAsync(string hashKey, string field)
+ {
+ // получить значение поля из Hash
+ var value = await redis.HashGetAsync(hashKey, field);
+
+ if (value.IsNullOrEmpty)
+ return default;
+
+ return JsonSerializer.Deserialize(value);
+ }
+
+ public async Task> GetAllHashFieldsAsync(string hashKey)
+ {
+ // получить все записи из Hash
+ var objs = await redis.HashGetAllAsync(hashKey);
+
+ if (objs.Length == 0)
+ return new Dictionary();
+
+ var result = objs.ToDictionary(
+ t => t.Name.ToString(),
+ t => JsonSerializer.Deserialize(t.Value)
+ );
+
+ return result!;
+ }
+
+ public async Task DeleteHashFieldAsync(string hashKey, string field)
+ {
+ // удалить запись из Hash
+ await redis.HashDeleteAsync(hashKey, field);
+ }
+
+ public async Task HashFieldExistsAsync(string hashKey, string field)
+ {
+ // есть ли запись в Hash
+ return await redis.HashExistsAsync(hashKey, field);
+ }
+
+ public async Task DeleteHashAsync(string hashKey)
+ {
+ // удалить весь Hash
+ await redis.KeyDeleteAsync(hashKey);
+ }
+
+ public async Task GetHashLengthAsync(string hashKey)
+ {
+ // кол-во записей в hash
+ return await redis.HashLengthAsync(hashKey);
+ }
+
+ public async Task SetHashTtlAsync(string hashKey, TimeSpan ttl)
+ {
+ // Установить ttl для Hash
+ await redis.KeyExpireAsync(hashKey, ttl);
+ }
+
+ #endregion
+
+ #region Helpers
public string GetKey(string[] keyParts, bool isUseHash = false)
{
@@ -91,5 +179,7 @@ namespace PARR.DAL.Cache.Services.Base
return keyStr;
}
+ #endregion
+
}
}
diff --git a/PARR.DAL/ParrDalInstaller.cs b/PARR.DAL/ParrDalInstaller.cs
index 5a92befb..f858bb7a 100644
--- a/PARR.DAL/ParrDalInstaller.cs
+++ b/PARR.DAL/ParrDalInstaller.cs
@@ -24,6 +24,7 @@ using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Schedule;
using PARR.DAL.Services.Interfaces.Unit;
using PARR.DAL.Settings;
+using StackExchange.Redis;
namespace PARR.DAL
{
@@ -45,16 +46,24 @@ namespace PARR.DAL
#region Redis + cache services
+ services.AddSingleton(sp =>
+ {
+ // IConnectionMultiplexer - для нативных операций Redis
+ var connectionString = configuration.GetConnectionString("RedisConnection");
+ return ConnectionMultiplexer.Connect(connectionString);
+ });
+
services.AddStackExchangeRedisCache(opt =>
{
opt.Configuration = configuration.GetConnectionString("RedisConnection");
});
+
var groupedShortcodesCacheSettings = new GroupedShortcodesCacheSettings();
configuration.GetSection(nameof(GroupedShortcodesCacheSettings)).Bind(groupedShortcodesCacheSettings);
services.AddSingleton(groupedShortcodesCacheSettings);
- services.AddTransient();
+ services.AddSingleton();
#endregion