Update vari x gestione redis ottimizzata

This commit is contained in:
Samuele Locatelli
2025-07-24 18:59:00 +02:00
parent d9523c6bac
commit 3935bfcd8f
9 changed files with 102 additions and 121 deletions
+50 -77
View File
@@ -1,18 +1,10 @@
using EgwCoreLib.Razor;
using IOB_MAN.Core;
using IOB_MAN.Core.DTO;
using Microsoft.Extensions.Configuration;
using IOB_MAN.Core.DTO;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Channels;
namespace IOB_MAN.Core.Data
{
@@ -44,14 +36,15 @@ namespace IOB_MAN.Core.Data
{
// init REDIS obj
RedisConnMPlex = redisMultiplex;
RedisDb = this.RedisConnMPlex.GetDatabase();
RedisDb = RedisConnMPlex.GetDatabase();
RedisSubs = RedisConnMPlex.GetSubscriber();
// 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
};
// init classe sottoscrizione PubSub CHannel messages REDIS
messageDisp.Subscribe(ChannelName(codIob), (channel, message) =>
RedisSubs.Subscribe(ChannelName(codIob), (channel, message) =>
{
SaveIobStatus(channel, message);
});
@@ -486,8 +479,10 @@ namespace IOB_MAN.Core.Data
{
for (int i = 0; i < numAnsw; i++)
{
Int32.TryParse(valori[i], out currVal);
answ.Add(new KeyValuePair<string, int>(chiavi[i], currVal));
if (int.TryParse(valori[i], out currVal))
{
answ.Add(new KeyValuePair<string, int>($"{chiavi[i]}", currVal));
}
}
}
catch (Exception exc)
@@ -536,8 +531,11 @@ namespace IOB_MAN.Core.Data
int i = 0;
foreach (HashEntry item in valori)
{
answ[i] = new KeyValuePair<string, string>(item.Name, item.Value);
i++;
if (item.Name.HasValue)
{
answ[i] = new KeyValuePair<string, string>($"{item.Name}", $"{item.Value}");
i++;
}
}
}
catch (Exception exc)
@@ -562,7 +560,10 @@ namespace IOB_MAN.Core.Data
HashEntry[] valori = RedisDb.HashGetAll(chiave);
foreach (HashEntry item in valori)
{
answ.Add(item.Name, item.Value);
if (item.Name.HasValue)
{
answ.Add($"{item.Name}", $"{item.Value}");
}
}
}
catch (Exception exc)
@@ -693,7 +694,7 @@ namespace IOB_MAN.Core.Data
int i = 0;
foreach (KeyValuePair<string, string> kvp in hashFields)
{
valori[i] = new HashEntry(kvp.Key, kvp.Value);
valori[i] = new HashEntry($"{kvp.Key}", $"{kvp.Value}");
i++;
}
RedisDb.HashSet(chiave, valori);
@@ -753,7 +754,7 @@ namespace IOB_MAN.Core.Data
int i = 0;
foreach (KeyValuePair<string, string> kvp in hashFields)
{
valori[i] = new HashEntry(kvp.Key, kvp.Value);
valori[i] = new HashEntry($"{kvp.Key}", $"{kvp.Value}");
i++;
}
RedisDb.HashSet(chiave, valori);
@@ -805,27 +806,22 @@ namespace IOB_MAN.Core.Data
public bool redSaveHashList(string hashKey, List<KeyValuePair<string, string>> hashListKVP)
{
bool answ = false;
if (RedisConnMPlex.IsConnected)
try
{
// cerco se ci sia valore in redis...
IDatabase cache = RedisConnMPlex.GetDatabase();
try
RedisKey chiave = hashKey;
HashEntry[] valori = new HashEntry[hashListKVP.Count];
int i = 0;
foreach (KeyValuePair<string, string> kvp in hashListKVP)
{
RedisKey chiave = hashKey;
HashEntry[] valori = new HashEntry[hashListKVP.Count];
int i = 0;
foreach (KeyValuePair<string, string> kvp in hashListKVP)
{
valori[i] = new HashEntry(kvp.Key, kvp.Value);
i++;
}
cache.HashSet(chiave, valori);
answ = true;
}
catch (Exception exc)
{
Log.Error($"redSaveHashList:{Environment.NewLine}{exc}");
valori[i] = new HashEntry(kvp.Key, kvp.Value);
i++;
}
RedisDb.HashSet(chiave, valori);
answ = true;
}
catch (Exception exc)
{
Log.Error($"redSaveHashList:{Environment.NewLine}{exc}");
}
return answ;
}
@@ -970,34 +966,6 @@ namespace IOB_MAN.Core.Data
#endregion Public Methods
#region Protected Properties
/// <summary>
/// Message Dispatcher: oggetto comunicazione pub/sub via REDIS channels corrente
/// </summary>
protected ISubscriber messageDisp
{
get
{
ISubscriber answ;
// se già valorizzato uso oggetto private...
if (_currSub != null)
{
answ = _currSub;
}
else
{
// sottoscrizione al dispatcher messaggi
answ = RedisConnMPlex.GetSubscriber();
_currSub = answ;
}
// restituisco oggetto DB
return answ;
}
}
#endregion Protected Properties
#region Protected Methods
protected void CleanExpiredEvents(string rkeyTS, string rkeyHash, int minutesBack, int batchSize = 1000)
@@ -1224,12 +1192,13 @@ namespace IOB_MAN.Core.Data
private double lastFLRatio = 0;
#if DEBUG
private long NumChannelCall = 0;
private long NumReadCache = 0;
private long NumReadLast = 0;
private long NumReadPubSub = 0;
#endif
/// <summary>
/// Random genertor
@@ -1252,24 +1221,27 @@ namespace IOB_MAN.Core.Data
private IDatabase RedisDb = null!;
/// <summary>
/// Hash redis x dati server
/// Message Dispatcher: oggetto comunicazione pub/sub via REDIS channels corrente
/// </summary>
private string RedServKey = "";
private ISubscriber RedisSubs;
#if DEBUG
#endif
/// <summary>
/// Hash redis x dati MAN
/// </summary>
private string RedManKey = "";
/// <summary>
/// Hash redis x dati server
/// </summary>
private string RedServKey = "";
#endregion Private Fields
#region Private Properties
/// <summary>
/// Oggetto subscriber x pubblicazione/sottoscrizione canali REDIS
/// </summary>
private ISubscriber _currSub { get; set; } = null!;
/// <summary>
/// Verifica validità dati channel (quando refresh ricevuto entro periodo validità)
/// </summary>
@@ -1290,9 +1262,11 @@ namespace IOB_MAN.Core.Data
#region Private Methods
private string ChannelName(string codIob)
private RedisChannel ChannelName(string codIob)
{
return $"IobChannel_{codIob}";
string chName = $"IobChannel_{codIob}";
RedisChannel rChannel = new RedisChannel($"IobChannel_{codIob}", RedisChannel.PatternMode.Literal);
return rChannel;
}
/// <summary>
@@ -1588,6 +1562,5 @@ namespace IOB_MAN.Core.Data
}
#endregion Private Methods
}
}
+11 -12
View File
@@ -9,18 +9,6 @@ namespace IOB_MAN.Core
{
public class IobAdapt : IDisposable
{
public void Dispose()
{
CodIOB = "";
pID = 0;
ExeName = "";
TgtName = "";
isRunning = false;
// initi redis
redisMan = null;
GC.Collect();
}
#region Public Constructors
/// <summary>
@@ -228,6 +216,17 @@ namespace IOB_MAN.Core
#endregion Public Properties
#region Public Methods
public void Dispose()
{
isRunning = false;
redisMan = null;
GC.Collect();
}
#endregion Public Methods
#region Protected Fields
protected int maxVeto = 3000;
+2 -2
View File
@@ -1080,8 +1080,8 @@ namespace IOB_MAN.Core.Services
if (!File.Exists(item.Value.NLogPath))
{
// verifico folder parent...
string parentDir = Path.GetDirectoryName(item.Value.NLogPath);
if (!Directory.Exists(parentDir))
string parentDir = Path.GetDirectoryName(item.Value.NLogPath) ?? "";
if (!string.IsNullOrEmpty(parentDir) && !Directory.Exists(parentDir))
{
Directory.CreateDirectory(parentDir);
}
+4 -1
View File
@@ -333,7 +333,10 @@ namespace IOB_MAN.Core.Services
HashEntry[] valori = RedisDb.HashGetAll(chiave);
foreach (HashEntry item in valori)
{
answ.Add(item.Name, item.Value);
if (item.Name.HasValue && item.Value.HasValue)
{
answ.Add($"{item.Name}", $"{item.Value}");
}
}
}
catch (Exception exc)
@@ -72,7 +72,6 @@
<div class="card-body px-2 py-1">
@if (dxMenuVisible)
{
@* <ul class="dropdown-menu" style="@contextMenuStyle"> *@
<ul class="list-group small" style="@contextMenuStyle">
@if (selIOB != null && !string.IsNullOrEmpty(selIOB.CodIOB))
{
@@ -83,15 +82,15 @@
<li class="list-group-item list-group-item-primary" @onclick="() => OpenFLForm()"><i class="fa-solid fa-gear me-2"></i> @selIOB.CodIOB | Pareto FluxLog + Config</li>
<button type="button" class="list-group-item list-group-item-action list-group-item-danger" @onclick="() => DoCloseChild(selIOB)"><i class="fa-solid fa-stop me-2 text-danger"></i> <b>Close</b> @selIOB.CodIOB</button>
}
else
@* else
{
<button type="button" class="list-group-item list-group-item-action list-group-item-success disabled"><i class="fa-solid fa-play me-2 text-success"></i> <b>Restart</b> @selIOB.CodIOB</button>
<button type="button" class="list-group-item list-group-item-action list-group-item-success disabled"><i class="fa-solid fa-play me-2 text-success"></i> <b>Restart</b> IOB</button>
<button type="button" class="list-group-item list-group-item-action list-group-item-info2 disabled"><i class="fa-solid fa-folder-open me-2"></i> Open <b>LOG</b> Folder</button>
<button type="button" class="list-group-item list-group-item-action list-group-item-secondary2 disabled"><i class="fa-solid fa-folder-open me-2"></i> Open <b>CONF</b> Folder</button>
<button type="button" class="list-group-item list-group-item-action list-group-item-success2 disabled"><i class="fa-solid fa-folder-open me-2"></i> Open <b>APP</b> Folder</button>
<li class="list-group-item list-group-item-primary disabled"><i class="fa-solid fa-gear me-2"></i> @selIOB.CodIOB | Pareto FluxLog + Config</li>
<button type="button" class="list-group-item list-group-item-action list-group-item-danger disabled"><i class="fa-solid fa-stop me-2 text-danger"></i> <b>Close</b> @selIOB.CodIOB</button>
}
<li class="list-group-item list-group-item-primary disabled"><i class="fa-solid fa-gear me-2"></i> IOB | Pareto FluxLog + Config</li>
<button type="button" class="list-group-item list-group-item-action list-group-item-danger disabled"><i class="fa-solid fa-stop me-2 text-danger"></i> <b>Close</b> IOB</button>
} *@
</ul>
}
@@ -337,7 +337,10 @@ namespace IOB_MAN.Components.Compo
private string countAutoRestart = "";
#if false
private int currVal = 100;
private int nextVal = 100;
#endif
private bool dxMenuVisible = false;
@@ -347,7 +350,6 @@ namespace IOB_MAN.Components.Compo
private string menuYpx = "0px";
private int nextVal = 100;
private IobAdapt? selIOB = null;
@@ -22,7 +22,7 @@ namespace IOB_MAN.Components.Compo
get => searchRecords;
set
{
if (searchRecords != value)
if (!searchRecords.Equals(value))
{
currSelId = "";
searchRecords = value;
@@ -30,8 +30,6 @@ namespace IOB_MAN.Components.Compo
}
}
private List<FluxLogStatsDTO.ParetoVals> searchRecords { get; set; } = new List<FluxLogStatsDTO.ParetoVals>();
#endregion Public Properties
#region Protected Properties
@@ -42,15 +40,16 @@ namespace IOB_MAN.Components.Compo
#region Protected Methods
protected string CssCheckSelect(FluxLogStatsDTO.ParetoVals currRec)
{
return currRec.Valore == currSelId ? "active" : "";
}
protected string CssBadge(FluxLogStatsDTO.ParetoVals currRec)
{
return currRec.Valore == currSelId ? "text-bg-dark" : "text-bg-primary";
}
protected string CssCheckSelect(FluxLogStatsDTO.ParetoVals currRec)
{
return currRec.Valore == currSelId ? "active" : "";
}
protected override void OnParametersSet()
{
ForceReload();
@@ -96,16 +95,19 @@ namespace IOB_MAN.Components.Compo
#region Private Fields
private int currPage = 0;
private string currSelId = "";
private bool isLoading = false;
private int numRecord = 10;
private int totalCount = 0;
#endregion Private Fields
#region Private Properties
private List<FluxLogStatsDTO.ParetoVals> searchRecords { get; set; } = new List<FluxLogStatsDTO.ParetoVals>();
#endregion Private Properties
#region Private Methods
private void ForceReload()
+14 -11
View File
@@ -230,18 +230,21 @@ namespace IOB_MAN.Components.Pages
DateTime adesso = DateTime.Now;
// faccio backup
string fileNameOnly = Path.GetFileName(currConfFile);
string baseDir = Path.GetDirectoryName(currConfFile);
string bcfFile = Path.Combine(baseDir, $"{fileNameOnly}_{adesso:yyMMdd-HHmmss}.bck");
File.Copy(currConfFile, bcfFile);
// serializzo e salvo...
JsonSerializerSettings jsSet = new JsonSerializerSettings()
string baseDir = Path.GetDirectoryName(currConfFile) ?? "";
if (!string.IsNullOrEmpty(baseDir))
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
Culture = CultureInfo.InvariantCulture
};
string rawData = JsonConvert.SerializeObject(currMem, jsSet);
File.WriteAllText(currConfFile, rawData);
string bcfFile = Path.Combine(baseDir, $"{fileNameOnly}_{adesso:yyMMdd-HHmmss}.bck");
File.Copy(currConfFile, bcfFile);
// serializzo e salvo...
JsonSerializerSettings jsSet = new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
Culture = CultureInfo.InvariantCulture
};
string rawData = JsonConvert.SerializeObject(currMem, jsSet);
File.WriteAllText(currConfFile, rawData);
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<Version>4.0.2507.2107</Version>
<Version>4.0.2507.2418</Version>
<Configurations>Debug;Release;Remote_DEBUG</Configurations>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>