From aff6a89b73da220a42becfd613f11f31b964f3ff Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Fri, 26 May 2023 18:01:35 +0200 Subject: [PATCH] Inizio sistemazione cache redis x utenti --- Resources/manifest.xml | 2 +- WebDoorCreator.Core/Constants.cs | 1 + .../Services/WebDoorCreatorService.cs | 11 +- WebDoorCreator.UI/Data/WDCUserService.cs | 202 +++++++++++++++++- 4 files changed, 203 insertions(+), 13 deletions(-) diff --git a/Resources/manifest.xml b/Resources/manifest.xml index 8fc32af..78acb42 100644 --- a/Resources/manifest.xml +++ b/Resources/manifest.xml @@ -1,7 +1,7 @@ 0.9.2305.2617 - http://nexus.steamware.net/repository/SWS/WDC/stable/WDC.UI.zip + http://nexus.steamware.net/repository/SWS/WDC/stable/WDC.API.zip http://nexus.steamware.net/repository/SWS/WDC/stable/ChangeLog.html false diff --git a/WebDoorCreator.Core/Constants.cs b/WebDoorCreator.Core/Constants.cs index 3883d1b..1670971 100644 --- a/WebDoorCreator.Core/Constants.cs +++ b/WebDoorCreator.Core/Constants.cs @@ -49,6 +49,7 @@ namespace WebDoorCreator.Core public const string rKeyOrderStatus = $"{redisBaseAddr}:Cache:OrderStatus"; public const string rKeyRoles = $"{redisBaseAddr}:Cache:Roles"; public const string rKeyUsers = $"{redisBaseAddr}:Cache:Users"; + public const string rKeyUsersAll = $"{redisBaseAddr}:Cache:UsersAll"; public const string rKeyUsersView = $"{redisBaseAddr}:Cache:UsersView"; public const string rKeyVocLemma = $"{redisBaseAddr}:Cache:VocLemma"; public const string rKeyLanguage = $"{redisBaseAddr}:Cache:Languages"; diff --git a/WebDoorCreator.Data/Services/WebDoorCreatorService.cs b/WebDoorCreator.Data/Services/WebDoorCreatorService.cs index 2fb80fc..147ef49 100644 --- a/WebDoorCreator.Data/Services/WebDoorCreatorService.cs +++ b/WebDoorCreator.Data/Services/WebDoorCreatorService.cs @@ -2280,12 +2280,6 @@ namespace WebDoorCreator.Data.Services #endregion Public Methods - #region Protected Fields - - protected Random rnd = new Random(); - - #endregion Protected Fields - #region Protected Properties protected WebDoorCreator.Data.DDF.Converter currDdfConv { get; set; } = null!; @@ -2295,11 +2289,8 @@ namespace WebDoorCreator.Data.Services #region Private Fields private static IConfiguration _configuration = null!; - private static JsonSerializerSettings? JSSettings; - private static Logger Log = LogManager.GetCurrentClassLogger(); - private readonly IEmailSender _emailSender; /// @@ -2322,6 +2313,8 @@ namespace WebDoorCreator.Data.Services /// private IDatabase redisDb = null!; + private Random rnd = new Random(); + #endregion Private Fields #region Private Properties diff --git a/WebDoorCreator.UI/Data/WDCUserService.cs b/WebDoorCreator.UI/Data/WDCUserService.cs index 8e7824d..3f63e1a 100644 --- a/WebDoorCreator.UI/Data/WDCUserService.cs +++ b/WebDoorCreator.UI/Data/WDCUserService.cs @@ -1,4 +1,14 @@ using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; +using NLog; +using NLog.Fluent; +using Org.BouncyCastle.Asn1.X500; +using StackExchange.Redis; +using System.Diagnostics; +using WebDoorCreator.Core; +using WebDoorCreator.Data.DbModels; using WebDoorCreator.Data.User; namespace WebDoorCreator.UI.Data @@ -7,9 +17,102 @@ namespace WebDoorCreator.UI.Data { #region Public Constructors - public WDCUserService(UserManager userManager) + private static Logger Log = LogManager.GetCurrentClassLogger(); + /// + /// Durata cache lunga IN SECONDI + /// + private int cacheTtlLong = 60 * 5; + + /// + /// Durata cache breve IN SECONDI + /// + private int cacheTtlShort = 60 * 1; + + /// + /// Oggetto per connessione a REDIS + /// + private IConnectionMultiplexer redisConn; + + /// + /// Oggetto DB redis da impiegare x chiamate R/W + /// + private IDatabase redisDb = null!; + + private static JsonSerializerSettings? JSSettings; + /// + /// Durata cache breve (1 min circa + perturbazione percentuale +/-10%) + /// + private TimeSpan FastCache + { + get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000); + } + + /// + /// Durata cache lunga (+ perturbazione percentuale +/-10%) + /// + private TimeSpan LongCache + { + get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000); + } + + /// + /// Durata cache molto breve (10 sec circa + perturbazione percentuale +/-10%) + /// + private TimeSpan UltraFastCache + { + get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000); + } + + /// + /// Durata cache lunga (+ perturbazione percentuale +/-10%) + /// + private TimeSpan UltraLongCache + { + get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000); + } + private Random rnd = new Random(); + + /// + /// Esegue flush memoria redis dato pattern + /// + /// + /// + private async Task ExecFlushRedisPattern(RedisValue pattern) + { + bool answ = false; + var listEndpoints = redisConn.GetEndPoints(); + foreach (var endPoint in listEndpoints) + { + //var server = redisConnAdmin.GetServer(listEndpoints[0]); + var server = redisConn.GetServer(endPoint); + if (server != null) + { + var keyList = server.Keys(redisDb.Database, pattern); + foreach (var item in keyList) + { + await redisDb.KeyDeleteAsync(item); + } + answ = true; + } + } + + return answ; + } + + public WDCUserService(IConnectionMultiplexer redisConnMult, UserManager userManager) { _userManager = userManager; + // Conf cache + redisConn = redisConnMult; + redisDb = this.redisConn.GetDatabase(); + + // json serializer... FIX errore loop circolare https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/ + JSSettings = new JsonSerializerSettings() + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }; + // chiudo log + Log.Info("Avviata classe WDCUserService"); } #endregion Public Constructors @@ -102,7 +205,51 @@ namespace WebDoorCreator.UI.Data #region Public Methods /// - /// Dati utente (filtrati da searchVal) + /// Dati utente (TUTTI) da REDIS o DB + /// + /// + public async Task> UserDataGetAll() + { + string source = "DB"; + + List dbResult = new List(); + // cerco da cache + string currKey = $"{Constants.rKeyUsersAll}"; + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + string? rawData = await redisDb.StringGetAsync(currKey); + if (!string.IsNullOrEmpty(rawData)) + { + source = "REDIS"; + var tempResult = JsonConvert.DeserializeObject>(rawData); + if (tempResult == null) + { + dbResult = new List(); + } + else + { + dbResult = tempResult; + } + } + else + { + dbResult = await _userManager.Users.ToListAsync(); + rawData = JsonConvert.SerializeObject(dbResult, JSSettings); + await redisDb.StringSetAsync(currKey, rawData, LongCache); + } + if (dbResult == null) + { + dbResult = new List(); + } + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Debug($"UserDataGetAll | {source} in: {ts.TotalMilliseconds} ms"); + return dbResult; + } + + + /// + /// Dati utente (filtrati da UserId) /// /// /// @@ -111,8 +258,11 @@ namespace WebDoorCreator.UI.Data // Collezione utenti List RawList = new List(); List UsersList = new List(); +#if false // recupero utenti da obj _userManager - var allData = _userManager.Users.ToList(); + var allData = _userManager.Users.ToList(); +#endif + var allData = await UserDataGetAll(); if (!string.IsNullOrEmpty(searchVal)) { RawList = allData.Where(x => x.NormalizedEmail.Contains(searchVal.ToUpper()) || x.NormalizedUserName.Contains(searchVal.ToUpper())).ToList(); @@ -147,6 +297,52 @@ namespace WebDoorCreator.UI.Data return await Task.FromResult(UsersList); } + /// + /// Dati utente (singolo x UserId) + /// + /// + /// + public async Task> UserDataGetById(string UserId) + { + // Collezione utenti + List RawList = new List(); + List UsersList = new List(); + // recupero utenti da obj _userManager + var allData = _userManager.Users.ToList(); + if (!string.IsNullOrEmpty(UserId)) + { + RawList = allData.Where(x => x.NormalizedEmail.Contains(UserId.ToUpper()) || x.NormalizedUserName.Contains(UserId.ToUpper())).ToList(); + } + else + { + RawList = allData; + } + var user = RawList.Select(x => new IdentityUser + { + Id = x.Id, + UserName = x.UserName, + Email = x.Email, + PhoneNumber = x.PhoneNumber, + PasswordHash = "*****", + EmailConfirmed = x.EmailConfirmed + }).ToList(); + + foreach (var item in user) + { + var UserRoles = await _userManager.GetRolesAsync(item); + var UserClaims = await _userManager.GetClaimsAsync(item); + + var newItem = new UserData() + { + Identity = item, + Roles = UserRoles.ToList(), + Claims = UserClaims.ToList() + }; + UsersList.Add(newItem); + } + return await Task.FromResult(UsersList); + } + #endregion Public Methods #region Protected Methods