diff --git a/MP-TAB3/MP-TAB3.csproj b/MP-TAB3/MP-TAB3.csproj
index 65364cf6..a9d0c0cd 100644
--- a/MP-TAB3/MP-TAB3.csproj
+++ b/MP-TAB3/MP-TAB3.csproj
@@ -3,7 +3,7 @@
net8.0
enable
- 8.16.2606.1312
+ 8.16.2606.2208
enable
MP_TAB3
diff --git a/MP-TAB3/Resources/ChangeLog.html b/MP-TAB3/Resources/ChangeLog.html
index b09252cc..5711f4d3 100644
--- a/MP-TAB3/Resources/ChangeLog.html
+++ b/MP-TAB3/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MAPOSPEC
- Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
-
diff --git a/MP-TAB3/Resources/VersNum.txt b/MP-TAB3/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP-TAB3/Resources/VersNum.txt
+++ b/MP-TAB3/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP-TAB3/Resources/manifest.xml b/MP-TAB3/Resources/manifest.xml
index 4896b650..674d8a6c 100644
--- a/MP-TAB3/Resources/manifest.xml
+++ b/MP-TAB3/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/MP-TAB3.zip
https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/ChangeLog.html
false
diff --git a/MP.Data/Controllers/MpIocController.cs b/MP.Data/Controllers/MpIocController.cs
index f2520dfa..56705d1d 100644
--- a/MP.Data/Controllers/MpIocController.cs
+++ b/MP.Data/Controllers/MpIocController.cs
@@ -945,7 +945,6 @@ namespace MP.Data.Controllers
#region Private Fields
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
- private DbContextOptions optionsFlux;
#endregion Private Fields
}
diff --git a/MP.Data/DataServiceCollectionExtensions.cs b/MP.Data/DataServiceCollectionExtensions.cs
index 03a1f181..917d08de 100644
--- a/MP.Data/DataServiceCollectionExtensions.cs
+++ b/MP.Data/DataServiceCollectionExtensions.cs
@@ -55,6 +55,25 @@ namespace MP.Data
return services;
}
+ ///
+ /// Aggiunta repository/servizi specifici per RIOC
+ ///
+ ///
+ ///
+ public static IServiceCollection AddRIocDataLayer(this IServiceCollection services)
+ {
+
+ // Repository Scoped x registrazione statistiche chiamate
+ services.TryAddScoped();
+ services.TryAddScoped();
+
+ // Servizi Scoped statistiche
+ services.TryAddScoped();
+ services.TryAddScoped();
+
+ return services;
+ }
+
///
/// Aggiunta repository/servizi specifici per LAND
///
diff --git a/MP.Data/Services/IOC/IocService.cs b/MP.Data/Services/IOC/IocService.cs
index 8669e3e1..3e9abb08 100644
--- a/MP.Data/Services/IOC/IocService.cs
+++ b/MP.Data/Services/IOC/IocService.cs
@@ -557,7 +557,6 @@ namespace MP.Data.Services.IOC
///
private async Task IobSLogEnabAsync(string idxMacchina)
{
- bool answ = false;
// ORA recupero da memoria redis...
var rKey = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
RedisValue rawData = await _redisDb.HashGetAsync(rKey, (RedisValue)"sLogEnabled");
diff --git a/MP.IOC/Services/IWeightProvider.cs b/MP.Data/Services/RouteWeight/IWeightProvider.cs
similarity index 88%
rename from MP.IOC/Services/IWeightProvider.cs
rename to MP.Data/Services/RouteWeight/IWeightProvider.cs
index df2c4fa0..aa28bda4 100644
--- a/MP.IOC/Services/IWeightProvider.cs
+++ b/MP.Data/Services/RouteWeight/IWeightProvider.cs
@@ -1,6 +1,8 @@
using MP.Core.DTO;
+using System.Collections.Generic;
+using System.Threading.Tasks;
-namespace MP.IOC.Services
+namespace MP.Data.Services.RouteWeight
{
public interface IWeightProvider
{
diff --git a/MP.IOC/Services/InMemoryWeightProvider.cs b/MP.Data/Services/RouteWeight/InMemoryWeightProvider.cs
similarity index 82%
rename from MP.IOC/Services/InMemoryWeightProvider.cs
rename to MP.Data/Services/RouteWeight/InMemoryWeightProvider.cs
index d6885e51..16f022b6 100644
--- a/MP.IOC/Services/InMemoryWeightProvider.cs
+++ b/MP.Data/Services/RouteWeight/InMemoryWeightProvider.cs
@@ -1,14 +1,15 @@
-using MP.Core.DTO;
+using Microsoft.Extensions.Configuration;
+using MP.Core.DTO;
+using System;
using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading.Tasks;
-namespace MP.IOC.Services
+namespace MP.Data.Services.RouteWeight
{
-
public class InMemoryWeightProvider : IWeightProvider
{
- private readonly ConcurrentDictionary _map = new();
- private readonly int _defaultOld;
- private readonly int _defaultNew;
+ #region Public Constructors
public InMemoryWeightProvider(IConfiguration config)
{
@@ -16,16 +17,9 @@ namespace MP.IOC.Services
_defaultNew = config.GetValue("RouteMan:DefaultWeightNew", 0);
}
- public (int oldWeight, int newWeight) GetWeightsFor(string method)
- {
- if (string.IsNullOrEmpty(method)) method = "unknown";
- return _map.GetOrAdd(method, _ => (_defaultOld, _defaultNew));
- }
+ #endregion Public Constructors
- public void SetWeights(string method, int oldWeight, int newWeight)
- {
- _map[method] = (Math.Clamp(oldWeight, 0, 100), Math.Clamp(newWeight, 0, 100));
- }
+ #region Public Methods
public async Task
> GetAllWeightsAsync()
{
@@ -44,6 +38,17 @@ namespace MP.IOC.Services
return result;
}
+ public (int oldWeight, int newWeight) GetWeightsFor(string method)
+ {
+ if (string.IsNullOrEmpty(method)) method = "unknown";
+ return _map.GetOrAdd(method, _ => (_defaultOld, _defaultNew));
+ }
+
+ public void SetWeights(string method, int oldWeight, int newWeight)
+ {
+ _map[method] = (Math.Clamp(oldWeight, 0, 100), Math.Clamp(newWeight, 0, 100));
+ }
+
public bool UpsertWeight(WeightDTO updRecord)
{
if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
@@ -53,7 +58,15 @@ namespace MP.IOC.Services
return true;
}
+
+ #endregion Public Methods
+
+ #region Private Fields
+
+ private readonly int _defaultNew;
+ private readonly int _defaultOld;
+ private readonly ConcurrentDictionary _map = new();
+
+ #endregion Private Fields
}
-
-
-}
+}
\ No newline at end of file
diff --git a/MP.IOC/Services/RedisWeightProvider.cs b/MP.Data/Services/RouteWeight/RedisWeightProvider.cs
similarity index 53%
rename from MP.IOC/Services/RedisWeightProvider.cs
rename to MP.Data/Services/RouteWeight/RedisWeightProvider.cs
index 9daf4113..91caa478 100644
--- a/MP.IOC/Services/RedisWeightProvider.cs
+++ b/MP.Data/Services/RouteWeight/RedisWeightProvider.cs
@@ -1,14 +1,24 @@
-using MP.Core.DTO;
+using Microsoft.Extensions.Configuration;
+using MP.Core.DTO;
using StackExchange.Redis;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ZiggyCreatures.Caching.Fusion;
-namespace MP.IOC.Services
+namespace MP.Data.Services.RouteWeight
{
public class RedisWeightProvider : IWeightProvider
{
#region Public Constructors
- public RedisWeightProvider(IConnectionMultiplexer mux, IConfiguration config)
+ public RedisWeightProvider(
+ IConnectionMultiplexer mux,
+ IFusionCache cache,
+ IConfiguration config)
{
+ _cache = cache;
_config = config;
_db = mux.GetDatabase();
_mux = mux;
@@ -23,59 +33,16 @@ namespace MP.IOC.Services
#region Public Methods
///
- /// Ritorna (oldWeight, newWeight) per il metodo. Se non esiste, crea la chiave con i default.
+ /// Eliminazione esplicita cache data chiave
///
- public (int oldWeight, int newWeight) GetWeightsFor(string method)
+ ///
+ public void EvictLocalCacheFor(string method)
{
- if (string.IsNullOrEmpty(method)) method = "unknown";
- var key = _keyPrefix + method;
+ if (string.IsNullOrEmpty(method)) return;
- // Leggi entrambi i campi
- var oldVal = _db.HashGet(key, "old");
- var newVal = _db.HashGet(key, "new");
-
- // Se entrambi mancanti, inizializza con default (usando HSet con When.NotExists per evitare overwrite)
- if (oldVal.IsNull && newVal.IsNull)
- {
- // Imposta i campi singolarmente con When.NotExists per evitare overwrite
- _db.HashSet(key, "old", _defaultOld, When.NotExists);
- _db.HashSet(key, "new", _defaultNew, When.NotExists);
-
- // Rileggi per essere sicuri
- oldVal = _db.HashGet(key, "old");
- newVal = _db.HashGet(key, "new");
- }
-
- // Se uno dei due manca, impostalo al default (non sovrascrive l'altro)
- if (oldVal.IsNull)
- {
- _db.HashSet(key, "old", _defaultOld, When.NotExists);
- oldVal = _defaultOld;
- }
- if (newVal.IsNull)
- {
- _db.HashSet(key, "new", _defaultNew, When.NotExists);
- newVal = _defaultNew;
- }
-
- if (!int.TryParse(oldVal.ToString(), out var oldW)) oldW = _defaultOld;
- if (!int.TryParse(newVal.ToString(), out var newW)) newW = _defaultNew;
-
- // clamp 0..100
- oldW = Math.Clamp(oldW, 0, 100);
- newW = Math.Clamp(newW, 0, 100);
-
- return (oldW, newW);
- }
-
- // API per aggiornare i pesi a runtime (opzionale)
- public void SetWeights(string method, int oldWeight, int newWeight)
- {
- var key = _keyPrefix + (string.IsNullOrEmpty(method) ? "unknown" : method);
- _db.HashSet(key, new HashEntry[] {
- new HashEntry("old", Math.Clamp(oldWeight,0,100)),
- new HashEntry("new", Math.Clamp(newWeight,0,100))
- });
+ var cacheKey = $"weights:{method}";
+ // Rimuove la chiave dalla RAM (L1) dell'istanza corrente del Gateway
+ _cache.Remove(cacheKey);
}
public async Task> GetAllWeightsAsync()
@@ -117,20 +84,164 @@ namespace MP.IOC.Services
return result;
}
+ ///
+ /// Ritorna (oldWeight, newWeight) per il metodo con FusionCache e poi con dati Redis.
+ /// Se non esiste, crea la chiave con i default value.
+ ///
+ public (int oldWeight, int newWeight) GetWeightsFor(string method)
+ {
+ if (string.IsNullOrEmpty(method)) method = "unknown";
+
+ var cacheKey = $"weights:{method}";
+
+ // FusionCache gestisce L1, L2 e se non trova nulla esegue la factory sotto
+ var weights = _cache.GetOrSet(
+ cacheKey,
+ _ =>
+ {
+ // FACTORY DI INIZIALIZZAZIONE (Viene eseguita solo se la cache è vuota ovunque)
+ var redisKey = _keyPrefix + method;
+ var oldVal = _db.HashGet(redisKey, "old");
+ var newVal = _db.HashGet(redisKey, "new");
+
+ if (oldVal.IsNull && newVal.IsNull)
+ {
+ _db.HashSet(redisKey, "old", _defaultOld, When.NotExists);
+ _db.HashSet(redisKey, "new", _defaultNew, When.NotExists);
+ oldVal = _defaultOld;
+ newVal = _defaultNew;
+ }
+
+ if (oldVal.IsNull) { _db.HashSet(redisKey, "old", _defaultOld, When.NotExists); oldVal = _defaultOld; }
+ if (newVal.IsNull) { _db.HashSet(redisKey, "new", _defaultNew, When.NotExists); newVal = _defaultNew; }
+
+ if (!int.TryParse(oldVal.ToString(), out var oldW)) oldW = _defaultOld;
+ if (!int.TryParse(newVal.ToString(), out var newW)) newW = _defaultNew;
+
+ return new RouteWeights(Math.Clamp(oldW, 0, 100), Math.Clamp(newW, 0, 100));
+ },
+ // Durata specifica per questa tipologia di dato
+ options => options.SetDuration(TimeSpan.FromMinutes(10))
+ );
+
+ return (weights.OldWeight, weights.NewWeight);
+
+#if false
+ var key = _keyPrefix + method;
+
+ // Leggi entrambi i campi
+ var oldVal = _db.HashGet(key, "old");
+ var newVal = _db.HashGet(key, "new");
+
+ // Se entrambi mancanti, inizializza con default (usando HSet con When.NotExists per evitare overwrite)
+ if (oldVal.IsNull && newVal.IsNull)
+ {
+ // Imposta i campi singolarmente con When.NotExists per evitare overwrite
+ _db.HashSet(key, "old", _defaultOld, When.NotExists);
+ _db.HashSet(key, "new", _defaultNew, When.NotExists);
+
+ // Rileggi per essere sicuri
+ oldVal = _db.HashGet(key, "old");
+ newVal = _db.HashGet(key, "new");
+ }
+
+ // Se uno dei due manca, impostalo al default (non sovrascrive l'altro)
+ if (oldVal.IsNull)
+ {
+ _db.HashSet(key, "old", _defaultOld, When.NotExists);
+ oldVal = _defaultOld;
+ }
+ if (newVal.IsNull)
+ {
+ _db.HashSet(key, "new", _defaultNew, When.NotExists);
+ newVal = _defaultNew;
+ }
+
+ if (!int.TryParse(oldVal.ToString(), out var oldW)) oldW = _defaultOld;
+ if (!int.TryParse(newVal.ToString(), out var newW)) newW = _defaultNew;
+
+ // clamp 0..100
+ oldW = Math.Clamp(oldW, 0, 100);
+ newW = Math.Clamp(newW, 0, 100);
+
+ return (oldW, newW);
+#endif
+ }
+
+ // API per aggiornare i pesi a runtime (opzionale)
+ public void SetWeights(string method, int oldWeight, int newWeight)
+ {
+ // 1. Scrittura su Redis
+ var key = _keyPrefix + (string.IsNullOrEmpty(method) ? "unknown" : method);
+ _db.HashSet(key, new HashEntry[] {
+ new HashEntry("old", Math.Clamp(oldWeight,0,100)),
+ new HashEntry("new", Math.Clamp(newWeight,0,100))
+ });
+
+ // 2. Rimozione della chiave da FusionCache.
+ // Grazie al Backplane Pub/Sub, la RAM verrà azzerata istantaneamente su TUTTI i server.
+ var cacheKey = $"weights:{method}";
+ _cache.Remove(cacheKey);
+ }
+
public bool UpsertWeight(WeightDTO updRecord)
{
if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
return false;
- var key = _keyPrefix + updRecord.Method;
- _db.HashSet(key, new HashEntry[] {
- new HashEntry("old", Math.Clamp(updRecord.OldWeight, 0, 100)),
- new HashEntry("new", Math.Clamp(updRecord.NewWeight, 0, 100))
- });
+ // 1. Scrivi su Redis (Sorgente dati reale)
+ var redisKey = _keyPrefix + updRecord.Method;
+ _db.HashSet(redisKey, new HashEntry[] {
+ new HashEntry("old", Math.Clamp(updRecord.OldWeight, 0, 100)),
+ new HashEntry("new", Math.Clamp(updRecord.NewWeight, 0, 100))
+ });
+
+ // 2. Rimozione della chiave da FusionCache.
+ // Grazie al Backplane Pub/Sub, la RAM verrà azzerata istantaneamente su TUTTI i server.
+ var cacheKey = $"weights:{updRecord.Method}";
+ _cache.Remove(cacheKey);
return true;
+
+#if false
+ var key = _keyPrefix + updRecord.Method;
+ _db.HashSet(key, new HashEntry[] {
+ new HashEntry("old", Math.Clamp(updRecord.OldWeight, 0, 100)),
+ new HashEntry("new", Math.Clamp(updRecord.NewWeight, 0, 100))
+ });
+
+ return true;
+#endif
}
+ #endregion Public Methods
+
+ #region Private Fields
+
+ private static string _keyPrefix = "route_weight:";
+ private static string _redisBaseKey = "";
+ private readonly IFusionCache _cache;
+
+ ///
+ /// Definizione Record leggero per la cache
+ ///
+ ///
+ ///
+ public record RouteWeights(int OldWeight, int NewWeight);
+ private readonly IConfiguration _config;
+
+ private readonly IDatabase _db;
+
+ private readonly int _defaultNew;
+
+ private readonly int _defaultOld;
+
+ private readonly IConnectionMultiplexer _mux;
+
+ #endregion Private Fields
+
+ #region Private Methods
+
private string KeyToString(string key)
{
if (string.IsNullOrEmpty(key)) return "";
@@ -140,18 +251,6 @@ namespace MP.IOC.Services
return key;
}
- #endregion Public Methods
-
- #region Private Fields
-
- private static string _keyPrefix = "route_weight:";
- private static string _redisBaseKey = "";
- private readonly IConfiguration _config;
- private readonly IDatabase _db;
- private readonly IConnectionMultiplexer _mux;
- private readonly int _defaultNew;
- private readonly int _defaultOld;
-
- #endregion Private Fields
+ #endregion Private Methods
}
}
\ No newline at end of file
diff --git a/MP.INVE/MP.INVE.csproj b/MP.INVE/MP.INVE.csproj
index 6a3e6044..ab3c2e4a 100644
--- a/MP.INVE/MP.INVE.csproj
+++ b/MP.INVE/MP.INVE.csproj
@@ -5,7 +5,7 @@
enable
enable
MP.INVE
- 8.16.2606.1312
+ 8.16.2606.2208
diff --git a/MP.INVE/Resources/ChangeLog.html b/MP.INVE/Resources/ChangeLog.html
index 4a399a9e..60dd4771 100644
--- a/MP.INVE/Resources/ChangeLog.html
+++ b/MP.INVE/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MAPOINVE
- Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
-
diff --git a/MP.INVE/Resources/VersNum.txt b/MP.INVE/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.INVE/Resources/VersNum.txt
+++ b/MP.INVE/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.INVE/Resources/manifest.xml b/MP.INVE/Resources/manifest.xml
index d7fa5553..c735c0e1 100644
--- a/MP.INVE/Resources/manifest.xml
+++ b/MP.INVE/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/MP.INVE.zip
https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/ChangeLog.html
false
diff --git a/MP.IOC/Components/Pages/RouteConf.razor.cs b/MP.IOC/Components/Pages/RouteConf.razor.cs
index 35822888..d3547469 100644
--- a/MP.IOC/Components/Pages/RouteConf.razor.cs
+++ b/MP.IOC/Components/Pages/RouteConf.razor.cs
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MP.Core.DTO;
-using MP.IOC.Services;
+using MP.Data.Services.RouteWeight;
namespace MP.IOC.Components.Pages
{
diff --git a/MP.IOC/MP.IOC.csproj b/MP.IOC/MP.IOC.csproj
index 746511b7..da3199ee 100644
--- a/MP.IOC/MP.IOC.csproj
+++ b/MP.IOC/MP.IOC.csproj
@@ -4,9 +4,16 @@
net8.0
enable
enable
- 8.16.2606.2010
+ 8.16.2606.2208
+
+
+
+
+
+
+
diff --git a/MP.IOC/Program.cs b/MP.IOC/Program.cs
index 376940a2..bba091a0 100644
--- a/MP.IOC/Program.cs
+++ b/MP.IOC/Program.cs
@@ -4,10 +4,10 @@ using Microsoft.Extensions.Caching.Distributed;
using Microsoft.OpenApi.Models;
using MP.Core.Conf;
using MP.Data;
+using MP.Data.Services.RouteWeight;
using MP.IOC.Components;
using MP.IOC.Data;
using MP.IOC.Endpoints;
-using MP.IOC.Services;
using NLog;
using NLog.Web;
using StackExchange.Redis;
@@ -107,8 +107,8 @@ builder.Services.AddSingleton();
// 1. Registra il serializzatore NewtonsoftJson per FusionCache
builder.Services.AddSingleton(new FusionCacheNewtonsoftJsonSerializer());
-
// 2. Configura FusionCache (L1 Memory + L2 Redis Distributed + L3 DB via factory)
+//builder.Services.AddFusionCache("MAPO_MES_FusionCache")
builder.Services.AddFusionCache()
.WithDistributedCache(sp => sp.GetRequiredService())
.WithSerializer(new FusionCacheNewtonsoftJsonSerializer())
@@ -119,12 +119,15 @@ builder.Services.AddFusionCache()
.WithDefaultEntryOptions(options =>
{
// Durata di default dei dati in memoria
- options.Duration = TimeSpan.FromMinutes(1);
+ options.Duration = TimeSpan.FromMinutes(5);
// Jitter: variazione casuale alla scadenza per evitare scadenze in blocco
options.JitterMaxDuration = TimeSpan.FromSeconds(5);
});
+// aggiunta http client x chiamare REST esterne (reset cache su RIOC, in attesa fix fusionCache)
+builder.Services.AddHttpClient();
+
logger.Info("Standard service configured");
// WeightProvider: Redis/Memory da config
diff --git a/MP.IOC/Resources/ChangeLog.html b/MP.IOC/Resources/ChangeLog.html
index 05636903..2c7ed97b 100644
--- a/MP.IOC/Resources/ChangeLog.html
+++ b/MP.IOC/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MP-IOC
-
Versione: 8.16.2606.2010
+ Versione: 8.16.2606.2208
Note di rilascio:
-
diff --git a/MP.IOC/Resources/VersNum.txt b/MP.IOC/Resources/VersNum.txt
index eb7b715b..60d2cec2 100644
--- a/MP.IOC/Resources/VersNum.txt
+++ b/MP.IOC/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.2010
+8.16.2606.2208
diff --git a/MP.IOC/Resources/manifest.xml b/MP.IOC/Resources/manifest.xml
index 7436d253..040331cc 100644
--- a/MP.IOC/Resources/manifest.xml
+++ b/MP.IOC/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.2010
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip
https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html
false
diff --git a/MP.IOC/Services/BaseServ.cs b/MP.IOC/Services/BaseServ.cs
deleted file mode 100644
index a5420f14..00000000
--- a/MP.IOC/Services/BaseServ.cs
+++ /dev/null
@@ -1,372 +0,0 @@
-using MP.Data;
-using Newtonsoft.Json;
-using NLog;
-using StackExchange.Redis;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-
-namespace MP.IOC.Services
-{
-
- ///
- /// Classe base per i servizi che fornisce funzionalità comuni come
- /// - connessione a Redis
- /// - configurazione
- /// - gestione dei messaggi
- /// - strategie di caching.
- ///
- /// Questa classe agisce come modello per altri servizi derivati.
- ///
- public class BaseServ
- {
- #region Public Constructors
-
- ///
- /// Inizializza una nuova istanza della classe BaseServ.
- /// Configura la connessione Redis, carica le impostazioni di configurazione e inizializza il serializzatore JSON.
- ///
- /// Oggetto di configurazione per recuperare le impostazioni dell'applicazione.
- /// Multiplexer di connessione Redis per operazioni sul database.
- public BaseServ(IConfiguration Configuration, IConnectionMultiplexer RedisConn)
- {
- _config = Configuration;
- _redisConn = RedisConn;
- _redisDb = _redisConn.GetDatabase();
- // configuro la base key x la cache Redis, con verifica contenga Cache finale
- _redisBaseKey = _config.GetValue("ServerConf:RedisBaseKey") ?? "Lux:Cache";
- // aggiungo cache se non finisse per ":cache"
- if (!_redisBaseKey.EndsWith(":Cache"))
- {
- _redisBaseKey += ":Cache";
- }
-
- // Configurazione serializzatore JSON per risolvere errore di loop circolare
- JSSettings = new JsonSerializerSettings()
- {
- ReferenceLoopHandling = ReferenceLoopHandling.Ignore
- };
- }
-
- #endregion Public Constructors
-
- #region Public Properties
-
- ///
- /// Pipe dei messaggi per la comunicazione riguardo update calcolo BOM
- ///
- public MessagePipe PipeBom { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno HwList da Engine di calcolo verso interfaccia utente.
- /// I messaggi vengono inviati sul canale Redis definito da ChannelHwList.
- ///
- public MessagePipe PipeHwList { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno HwOptions calcolate da Engine di calcolo verso interfaccia utente.
- /// I messaggi vengono inviati sul canale Redis definito da ChannelHwOpt.
- ///
- public MessagePipe PipeHwOpt { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno PNG calcolati da Engine di calcolo verso interfaccia utente.
- /// I messaggi vengono inviati sul canale Redis definito da ChannelPng.
- ///
- public MessagePipe PipePng { get; set; } = null!;
-
- ///
- /// Canale informazioni relativo ad attività relative alla gesitone PROD:
- /// - carico macchine
- /// - scheduling
- ///
- public MessagePipe PipeProd { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno info elementi del profile
- ///
- public MessagePipe PipeProfElement { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno ProfileListAsync calcolate da Engine di calcolo verso interfaccia utente.
- /// I messaggi vengono inviati sul canale Redis definito da ChannelProfList.
- ///
- public MessagePipe PipeProfList { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno Shape calcolate da Engine di calcolo verso interfaccia utente.
- /// I messaggi vengono inviati sul canale Redis definito da ChannelShape.
- ///
- public MessagePipe PipeShape { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per ritorno SVG calcolati da Engine di calcolo verso interfaccia utente.
- /// I messaggi vengono inviati sul canale Redis definito da ChannelSvg.
- ///
- public MessagePipe PipeSvg { get; set; } = null!;
-
- ///
- /// Pipe dei messaggi per la comunicazione riguardo update generico UI
- ///
- public MessagePipe PipeUpdate { get; set; } = null!;
-
- #endregion Public Properties
-
- #region Protected Fields
-
- ///
- /// Oggetto per collezione dati Activity (span in Uptrace)
- ///
- protected static readonly ActivitySource ActivitySource = new ActivitySource("Lux.DATA");
-
- ///
- /// Oggetto logger utilizzato per registrare eventi e errori a livello di classe.
- /// Utile per il monitoraggio del comportamento dell'applicazione e la risoluzione di problemi.
- ///
- protected static Logger Log = LogManager.GetCurrentClassLogger();
-
- ///
- /// Oggetto di configurazione statico per accedere alle impostazioni dell'applicazione (es. stringhe di connessione).
- /// Condiviso tra tutte le istanze di BaseServ.
- ///
- protected readonly IConfiguration _config = null!;
-
- ///
- /// Path base chiavi REDIS
- ///
- protected readonly string _redisBaseKey = "Lux:Cache";
-
- ///
- /// Oggetto per la connessione a Redis utilizzato per operazioni di lettura/scrittura.
- ///
- protected readonly IConnectionMultiplexer _redisConn = null!;
-
- ///
- /// Database Redis utilizzato per le operazioni di lettura/scrittura
- /// nb: ottenuto tramite _redisConn.GetDatabase()
- ///
- protected readonly IDatabase _redisDb = null!;
-
- ///
- /// Abilitazione operazioni tracing generiche
- ///
- protected readonly bool _traceEnabled = false;
-
- ///
- /// Impostazioni del serializzatore JSON utilizzato per gestire oggetti con riferimenti circolari
- /// (es. oggetti che si fanno riferimento reciprocamente).
- ///
- protected JsonSerializerSettings? JSSettings;
-
- #endregion Protected Fields
-
- #region Protected Properties
-
- ///
- /// Durata della cache breve (circa 1 minuto + variazione del +/-10%)
- ///
- protected TimeSpan FastCache
- {
- get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000);
- }
-
- ///
- /// Durata della cache lunga (+ variazione del +/-10%)
- ///
- protected TimeSpan LongCache
- {
- get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000);
- }
-
- ///
- /// Durata della cache molto breve (circa 10 secondi + variazione del +/-10%)
- ///
- protected TimeSpan UltraFastCache
- {
- get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000);
- }
-
- ///
- /// Durata della cache molto lunga (+ variazione del +/-10%)
- ///
- protected TimeSpan UltraLongCache
- {
- get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000);
- }
-
- #endregion Protected Properties
-
- #region Protected Methods
-
- ///
- /// Helper avvio attività per la funzione tracciata
- ///
- ///
- ///
- protected static Activity? StartActivity([CallerMemberName] string? methodName = null)
- {
- var activity = ActivitySource.StartActivity(methodName ?? "UNDEF");
- activity?.SetTag("host.name", Environment.MachineName);
- return activity;
- }
-
- ///
- /// Invalida una o più chiavi/pattern in Redis
- ///
- protected async Task ClearCacheAsync(params string[] patterns)
- {
- foreach (var pattern in patterns)
- {
- // Chiamata al tuo metodo esistente
- await ExecFlushRedisPatternAsync((RedisValue)pattern);
- }
- }
-
- ///
- /// Metodo di flush dati cache Redis
- ///
- ///
- ///
- protected async Task ExecFlushRedisPatternAsync(RedisValue pattern)
- {
- // Qui inserisci la tua logica attuale (es. via Lua script o Keys/Scan)
- // Esempio rapido via server scan:
- var endpoints = _redisConn.GetEndPoints();
- foreach (var endpoint in endpoints)
- {
- var server = _redisConn.GetServer(endpoint);
- await foreach (var key in server.KeysAsync(_redisDb.Database, pattern))
- {
- await _redisDb.KeyDeleteAsync(key);
- }
- }
- }
-
- ///
- /// Helper generale di lettura da cache o da funzione (DB) con caching successivo
- ///
- ///
- ///
- ///
- ///
- ///
- protected async Task GetOrSetCacheAsync(string key, Func> factory, TimeSpan? expiration = null, [CallerMemberName] string? caller = null)
- {
- using var activity = StartActivity();
- string source = "DB";
-
- // 1. Provo Redis
- var cached = await _redisDb.StringGetAsync(key);
- if (cached.HasValue)
- {
- source = "REDIS";
- var cachedResult = JsonConvert.DeserializeObject(cached!)!;
-
- activity?.SetTag("data.source", source);
- LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms", NLog.LogLevel.Trace, caller);
-
- return cachedResult;
- }
-
- // 2. Chiamo il factory (DB)
- T result = await factory();
-
- if (result != null)
- {
- // 3. Salva in Redis per la prossima volta
- var serialized = JsonConvert.SerializeObject(result, JSSettings);
- await _redisDb.StringSetAsync(key, serialized, expiration ?? LongCache);
- }
-
- // sistemo activity tracking data
- activity?.SetTag("data.source", source);
- activity?.Stop();
-
- // log in console
- LogTrace($"GetOrSetCacheAsync | {source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds:N3}ms", NLog.LogLevel.Trace, caller);
-
- return result!;
- }
-
- ///
- /// Helper trace messaggio log (SE abilitato)
- ///
- ///
- ///
- ///
- protected void LogTrace(string traceMsg, NLog.LogLevel? reqLevel = null, [CallerMemberName] string? methodName = null)
- {
- if (!_traceEnabled)
- return;
-
- reqLevel ??= NLog.LogLevel.Debug;
-
- // Loggo!
- Log.Log(reqLevel, $"{methodName} | {traceMsg}");
- }
-
- ///
- /// Helper generale per la telemetria e gestione eccezioni
- ///
- ///
- ///
- ///
- ///
- ///
- protected async Task TraceAsync(string name, Func> body, object? parameters = null)
- {
- using var activity = ActivitySource.StartActivity(name);
- try
- {
- if (parameters != null)
- {
- activity?.SetTag("params", JsonConvert.SerializeObject(parameters));
- }
- var result = await body(activity);
- activity?.SetStatus(ActivityStatusCode.Ok);
- activity?.Stop();
- LogTrace($"TraceAsync | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms", methodName: name);
- return result;
- }
- catch (Exception ex)
- {
- activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
- //Log.Error(ex, "Errore in {MethodName}", name);
- LogTrace($"Errore in {name}", NLog.LogLevel.Error, name);
- throw; // Riesponi l'eccezione per il tracking globale
- }
- }
-
- #endregion Protected Methods
-
- #region Private Fields
-
- private static readonly ConcurrentDictionary _locks = new();
-
- ///
- /// Durata della cache lunga in secondi (predefinito: 5 minuti)
- /// Utilizzato nella proprietà LongCache per definire quanto a lungo i dati devono essere memorizzati in cache.
- ///
- private int cacheTtlLong = 60 * 5;
-
- ///
- /// Durata della cache breve in secondi (predefinito: 1 minuto)
- /// Utilizzato nelle proprietà FastCache e UltraFastCache per definire la durata della cache breve.
- ///
- private int cacheTtlShort = 60 * 1;
-
-
- ///
- /// Generatore di numeri casuali utilizzato per introdurre variabilità dinamica nelle durate della cache
- /// (simula variazioni reali nella freschezza dei dati e nei tempi di scadenza).
- ///
- private Random rnd = new Random();
-
- #endregion Private Fields
-
- #region Private Methods
-
-
- #endregion Private Methods
- }
-}
diff --git a/MP.IOC/appsettings.Production.json b/MP.IOC/appsettings.Production.json
index 787c7891..024c3541 100644
--- a/MP.IOC/appsettings.Production.json
+++ b/MP.IOC/appsettings.Production.json
@@ -16,6 +16,7 @@
"mdbConnString": "mongodb://localhost:27017"
},
"ServerConf": {
+ "GatewayPurgeUrl": "http://maposrv.egalware.com/MP/RIOC/api/admin/cache/purge-route/",
"useFactory": false
}
}
diff --git a/MP.IOC/appsettings.json b/MP.IOC/appsettings.json
index 4bd6bf3c..5edfaad4 100644
--- a/MP.IOC/appsettings.json
+++ b/MP.IOC/appsettings.json
@@ -64,6 +64,7 @@
},
"ServerConf": {
"BaseUrlIoc": "/MP/IOC/",
+ "GatewayPurgeUrl": "http://iis01.egalware.com/MP/RIOC/api/admin/cache/purge-route/",
"MpIoNS": "MoonPro:SQL2016DEV:MoonPro",
"RedisBaseKey": "MP-IOC",
"RedisWeight": true,
diff --git a/MP.Land/MP.Land.csproj b/MP.Land/MP.Land.csproj
index f8824d6e..99a04ebc 100644
--- a/MP.Land/MP.Land.csproj
+++ b/MP.Land/MP.Land.csproj
@@ -3,7 +3,7 @@
net8.0
MP.Land
- 8.16.2606.1312
+ 8.16.2606.2208
Debug;Release;Debug_LiManDebug
en
True
diff --git a/MP.Land/Resources/ChangeLog.html b/MP.Land/Resources/ChangeLog.html
index 7e4dedb9..fdd5899b 100644
--- a/MP.Land/Resources/ChangeLog.html
+++ b/MP.Land/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo Tablet MAPO - DotNet6
-
Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
diff --git a/MP.Land/Resources/VersNum.txt b/MP.Land/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.Land/Resources/VersNum.txt
+++ b/MP.Land/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.Land/Resources/manifest.xml b/MP.Land/Resources/manifest.xml
index ed12ccf8..dd962edb 100644
--- a/MP.Land/Resources/manifest.xml
+++ b/MP.Land/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/MP.Land.zip
https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/ChangeLog.html
false
diff --git a/MP.MON/MP.MON.csproj b/MP.MON/MP.MON.csproj
index ba22459c..91fac835 100644
--- a/MP.MON/MP.MON.csproj
+++ b/MP.MON/MP.MON.csproj
@@ -6,7 +6,7 @@
enable
MP.MON
$(AssemblyName.Replace(' ', '_'))
- 8.16.2606.1312
+ 8.16.2606.2208
diff --git a/MP.MON/Resources/ChangeLog.html b/MP.MON/Resources/ChangeLog.html
index b09252cc..5711f4d3 100644
--- a/MP.MON/Resources/ChangeLog.html
+++ b/MP.MON/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MAPOSPEC
- Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
-
diff --git a/MP.MON/Resources/VersNum.txt b/MP.MON/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.MON/Resources/VersNum.txt
+++ b/MP.MON/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.MON/Resources/manifest.xml b/MP.MON/Resources/manifest.xml
index 07216334..21eacd6e 100644
--- a/MP.MON/Resources/manifest.xml
+++ b/MP.MON/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/MP.MON.zip
https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/ChangeLog.html
false
diff --git a/MP.Prog/MP.Prog.csproj b/MP.Prog/MP.Prog.csproj
index 50d58df9..52e2d9f7 100644
--- a/MP.Prog/MP.Prog.csproj
+++ b/MP.Prog/MP.Prog.csproj
@@ -3,7 +3,7 @@
net8.0
MP.Prog
- 8.16.2606.1312
+ 8.16.2606.2208
True
diff --git a/MP.Prog/Resources/ChangeLog.html b/MP.Prog/Resources/ChangeLog.html
index 589576a7..5002c1d2 100644
--- a/MP.Prog/Resources/ChangeLog.html
+++ b/MP.Prog/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo gestione Programmi MAPO
-
Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
diff --git a/MP.Prog/Resources/VersNum.txt b/MP.Prog/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.Prog/Resources/VersNum.txt
+++ b/MP.Prog/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.Prog/Resources/manifest.xml b/MP.Prog/Resources/manifest.xml
index 2faec268..a46afa88 100644
--- a/MP.Prog/Resources/manifest.xml
+++ b/MP.Prog/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/MP.Prog.zip
https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/ChangeLog.html
false
diff --git a/MP.RIOC/MP.RIOC.csproj b/MP.RIOC/MP.RIOC.csproj
index d43f29e2..d8d563a5 100644
--- a/MP.RIOC/MP.RIOC.csproj
+++ b/MP.RIOC/MP.RIOC.csproj
@@ -5,10 +5,16 @@
enable
enable
MP.RIOC
- 8.16.2606.1312
+ 8.16.2606.2208
InProcess
+
+
+
+
+
+
diff --git a/MP.RIOC/Program.cs b/MP.RIOC/Program.cs
index a1f35daf..eac850df 100644
--- a/MP.RIOC/Program.cs
+++ b/MP.RIOC/Program.cs
@@ -1,7 +1,8 @@
using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.Extensions.Caching.Distributed;
using MP.Core.Conf;
using MP.Data;
+using MP.Data.Services.RouteWeight;
using MP.RIOC.Services;
using NLog;
using NLog.Web;
@@ -9,6 +10,10 @@ using StackExchange.Redis;
using System.Diagnostics;
using System.Net;
using System.Reflection;
+using ZiggyCreatures.Caching.Fusion;
+using ZiggyCreatures.Caching.Fusion.Backplane.StackExchangeRedis;
+using ZiggyCreatures.Caching.Fusion.Serialization;
+using ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson;
// Forza il ThreadPool a tenere pronti almeno 500 thread per i calcoli e 500 per l'I/O di rete
@@ -19,6 +24,11 @@ var builder = WebApplication.CreateBuilder(args);
// RECUPERO L'AMBIENTE REALE (Che ora IIS passa correttamente come 'Staging')
var env = builder.Environment;
+// recupero env corrente
+var logger = LogManager.Setup()
+ .LoadConfigurationFromAppSettings()
+ .GetCurrentClassLogger();
+
// FORZA IL CARICAMENTO CORRETTO DEI JSON CON LA GERARCHIA DI AMBIENTE
builder.Configuration
.SetBasePath(env.ContentRootPath)
@@ -26,10 +36,6 @@ builder.Configuration
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
-// recupero env corrente
-var logger = LogManager.Setup()
- .LoadConfigurationFromAppSettings()
- .GetCurrentClassLogger();
builder.Logging.ClearProviders();
builder.Host.UseNLog();
@@ -50,29 +56,14 @@ builder.Services.Configure(
builder.Configuration.GetSection("RedisScripts"));
logger.Info("RedisScript Provider configured");
-// Metodi principali x accesso dati
-var connStr = builder.Configuration.GetConnectionString("MP.Data")
- ?? throw new InvalidOperationException("ConnString 'MP.Data' mancante.");
-builder.Services.AddDbContextFactory(options =>
- options.UseSqlServer(connStr)
- .EnableSensitiveDataLogging(false) // true solo in Sviluppo
- .ConfigureWarnings(w => w.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning)));
-var connStrFL = builder.Configuration.GetConnectionString("MP.Flux")
- ?? throw new InvalidOperationException("ConnString 'MP.Flux' mancante.");
-builder.Services.AddDbContextFactory(options =>
- options.UseSqlServer(connStrFL)
- .EnableSensitiveDataLogging(false) // true solo in Sviluppo
- .ConfigureWarnings(w => w.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning)));
-
// MP.Data DbContext for Stats repositories
string utilsConnString = builder.Configuration.GetConnectionString("MP.Utils") ?? "Server=localhost;Database=MoonPro_Utils; integrated security=True; MultipleActiveResultSets=True; App=MP.IOC;";
builder.Services.AddDbContextFactory(options =>
options.UseSqlServer(utilsConnString));
// MP.Data Services Utils - Statistiche DB
-builder.Services.AddIocDataLayer();
+builder.Services.AddRIocDataLayer();
-// 1. Configurazione dell'invoker personalizzato (Risolve i tuoi errori)
// 1. Configurazione dell'invoker personalizzato (Potenziato con il Pooling)
var httpClientInvoker = new HttpMessageInvoker(new SocketsHttpHandler
{
@@ -109,8 +100,25 @@ builder.Services.AddHttpForwarder();
var redisMux = ConnectionMultiplexer.Connect(confRedis);
builder.Services.AddSingleton(redisMux);
-// registrazione FusionCache
-builder.Services.AddFusionCache();
+// 1. Registra il serializzatore NewtonsoftJson per FusionCache
+builder.Services.AddSingleton(new FusionCacheNewtonsoftJsonSerializer());
+// 2. Configura FusionCache (L1 Memory + L2 Redis Distributed + L3 DB via factory)
+//builder.Services.AddFusionCache("MAPO_MES_FusionCache")
+builder.Services.AddFusionCache()
+ .WithDistributedCache(sp => sp.GetRequiredService())
+ .WithSerializer(new FusionCacheNewtonsoftJsonSerializer())
+ .WithBackplane(new RedisBackplane(new RedisBackplaneOptions
+ {
+ ConnectionMultiplexerFactory = () => Task.FromResult(redisMux)
+ }))
+ .WithDefaultEntryOptions(options =>
+ {
+ // Durata di default dei dati in memoria
+ options.Duration = TimeSpan.FromMinutes(5);
+
+ // Jitter: variazione casuale alla scadenza per evitare scadenze in blocco
+ options.JitterMaxDuration = TimeSpan.FromSeconds(5);
+ });
// Registrazione dei servizi custom
builder.Services.AddSingleton();
@@ -175,6 +183,38 @@ app.Use(async (ctx, next) =>
await next();
});
+
+// test per ambiente di esecuzione InProcess...
+app.MapGet("api/alive", () =>
+ $"OK - Girando in: {System.Diagnostics.Process.GetCurrentProcess().ProcessName}");
+
+app.MapGet("/router-status", (RouteStatsManager stats) => Results.Ok(new
+{
+ Status = "Online",
+ Version = assemblyVersion,
+ Mode = weightOnRedis ? "Redis" : "InMemory",
+ Time = DateTime.Now,
+ Metrics = stats.Snapshot()
+}));
+
+// Endpoint per la rimozione mirata di una singola rotta dalla cache
+app.MapPost("/api/admin/cache/purge-route/{method}", (string method, IWeightProvider weightProvider) =>
+{
+ try
+ {
+ if (weightProvider is RedisWeightProvider redisProvider)
+ {
+ redisProvider.EvictLocalCacheFor(method);
+ return Results.Ok(new { Success = true, Message = $"Cache RAM per '{method}' svuotata." });
+ }
+ return Results.Problem("Provider non valido.");
+ }
+ catch (Exception ex)
+ {
+ return Results.Problem($"Errore: {ex.Message}");
+ }
+});
+
// 5. Il cuore del Proxy (MapWhen è terminale per le richieste che lo soddisfano)
string routePath = configuration.GetValue("ServerConf:RoutePath") ?? "/api/IOB";
string fullPath = $"{baseUrl}{routePath}".Replace("//", "/");
@@ -189,22 +229,10 @@ app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments(routePath, StringComparis
});
});
-// test per ambiente di esecuzione InProcess...
-app.MapGet("api/alive", () =>
- $"OK - Girando in: {System.Diagnostics.Process.GetCurrentProcess().ProcessName}");
// 6. Definizione degli Endpoints locali
app.MapRazorPages();
-app.MapGet("/router-status", (RouteStatsManager stats) => Results.Ok(new
-{
- Status = "Online",
- Version = assemblyVersion,
- Mode = weightOnRedis ? "Redis" : "InMemory",
- Time = DateTime.Now,
- Metrics = stats.Snapshot()
-}));
-
// 7. Fallback "intelligente"
// Invece di app.Run, usiamo MapFallback che viene eseguito SOLO se nessun altro endpoint o MapWhen ha risposto
app.MapFallback(async context =>
diff --git a/MP.RIOC/Properties/launchSettings.json b/MP.RIOC/Properties/launchSettings.json
index b57a323d..6d9aebb6 100644
--- a/MP.RIOC/Properties/launchSettings.json
+++ b/MP.RIOC/Properties/launchSettings.json
@@ -14,7 +14,7 @@
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "MP/RIOC/api/IOB/",
- "applicationUrl": "http://localhost:5290",
+ "applicationUrl": "http://*:5290",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@@ -24,7 +24,7 @@
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "MP/RIOC/api/IOB/",
- "applicationUrl": "https://localhost:7120;http://localhost:5290",
+ "applicationUrl": "https://*:7120;http://*:5290",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
diff --git a/MP.RIOC/Resources/ChangeLog.html b/MP.RIOC/Resources/ChangeLog.html
index ca5bc7eb..73dbdef8 100644
--- a/MP.RIOC/Resources/ChangeLog.html
+++ b/MP.RIOC/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MP-RIOC
-
Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
-
diff --git a/MP.RIOC/Resources/VersNum.txt b/MP.RIOC/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.RIOC/Resources/VersNum.txt
+++ b/MP.RIOC/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.RIOC/Resources/manifest.xml b/MP.RIOC/Resources/manifest.xml
index fd40f4f9..b6f74dac 100644
--- a/MP.RIOC/Resources/manifest.xml
+++ b/MP.RIOC/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/MP.RIOC.zip
https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/ChangeLog.html
false
diff --git a/MP.RIOC/Services/IWeightProvider.cs b/MP.RIOC/Services/IWeightProvider.cs
deleted file mode 100644
index b18e4fcb..00000000
--- a/MP.RIOC/Services/IWeightProvider.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using MP.Core.DTO;
-
-namespace MP.RIOC.Services
-{
- public interface IWeightProvider
- {
- #region Public Methods
-
- ///
- /// Ritorna l'intero elenco dei weight attivi nel formato WeightDTO
- ///
- ///
- Task
> GetAllWeightsAsync();
-
- ///
- /// Ritorna la coppia (oldWeight, newWeight) per scegliere dove instradare il metodo tra i 2 sistemi API.
- ///
- (int oldWeight, int newWeight) GetWeightsFor(string method);
-
- ///
- /// Aggiorna/Aggiuinge il valore del weight richiesto
- ///
- ///
- ///
- bool UpsertWeight(WeightDTO updRecord);
-
- #endregion Public Methods
- }
-}
diff --git a/MP.RIOC/Services/InMemoryWeightProvider.cs b/MP.RIOC/Services/InMemoryWeightProvider.cs
deleted file mode 100644
index f4baf415..00000000
--- a/MP.RIOC/Services/InMemoryWeightProvider.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MP.Core.DTO;
-using System.Collections.Concurrent;
-
-namespace MP.RIOC.Services
-{
- public class InMemoryWeightProvider : IWeightProvider
- {
- private readonly ConcurrentDictionary _map = new();
- private readonly int _defaultOld;
- private readonly int _defaultNew;
-
- public InMemoryWeightProvider(IConfiguration config)
- {
- _defaultOld = config.GetValue("RouteMan:DefaultWeightOld", 100);
- _defaultNew = config.GetValue("RouteMan:DefaultWeightNew", 0);
- }
-
- public (int oldWeight, int newWeight) GetWeightsFor(string method)
- {
- if (string.IsNullOrEmpty(method)) method = "unknown";
- return _map.GetOrAdd(method, _ => (_defaultOld, _defaultNew));
- }
-
- public void SetWeights(string method, int oldWeight, int newWeight)
- {
- _map[method] = (Math.Clamp(oldWeight, 0, 100), Math.Clamp(newWeight, 0, 100));
- }
-
- public async Task> GetAllWeightsAsync()
- {
- var result = new List();
- await Task.Delay(1);
-
- foreach (var kvp in _map)
- {
- result.Add(new WeightDTO
- {
- Method = kvp.Key,
- OldWeight = Math.Clamp(kvp.Value.oldW, 0, 100),
- NewWeight = Math.Clamp(kvp.Value.newW, 0, 100)
- });
- }
- return result;
- }
-
- public bool UpsertWeight(WeightDTO updRecord)
- {
- if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
- return false;
-
- _map[updRecord.Method] = (Math.Clamp(updRecord.OldWeight, 0, 100), Math.Clamp(updRecord.NewWeight, 0, 100));
-
- return true;
- }
- }
-}
diff --git a/MP.RIOC/Services/RedisWeightProvider.cs b/MP.RIOC/Services/RedisWeightProvider.cs
deleted file mode 100644
index e003c8e5..00000000
--- a/MP.RIOC/Services/RedisWeightProvider.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using MP.Core.DTO;
-using StackExchange.Redis;
-
-namespace MP.RIOC.Services
-{
- public class RedisWeightProvider : IWeightProvider
- {
- #region Public Constructors
-
- public RedisWeightProvider(IConnectionMultiplexer mux, IConfiguration config)
- {
- _config = config;
- _db = mux.GetDatabase();
- _mux = mux;
- _defaultOld = config.GetValue("RouteMan:DefaultWeightOld", 100);
- _defaultNew = config.GetValue("RouteMan:DefaultWeightNew", 0);
- _redisBaseKey = config.GetValue("ServerConf:RedisBaseKey") ?? "MP_IOC";
- _keyPrefix = $"{_redisBaseKey}:route_weight:";
- }
-
- #endregion Public Constructors
-
- #region Public Methods
-
- ///
- /// Ritorna (oldWeight, newWeight) per il metodo. Se non esiste, crea la chiave con i default.
- ///
- public (int oldWeight, int newWeight) GetWeightsFor(string method)
- {
- if (string.IsNullOrEmpty(method)) method = "unknown";
- var key = _keyPrefix + method;
-
- // Leggi entrambi i campi
- var oldVal = _db.HashGet(key, "old");
- var newVal = _db.HashGet(key, "new");
-
- // Se entrambi mancanti, inizializza con default (usando HSet con When.NotExists per evitare overwrite)
- if (oldVal.IsNull && newVal.IsNull)
- {
- // Imposta i campi singolarmente con When.NotExists per evitare overwrite
- _db.HashSet(key, "old", _defaultOld, When.NotExists);
- _db.HashSet(key, "new", _defaultNew, When.NotExists);
-
- // Rileggi per essere sicuri
- oldVal = _db.HashGet(key, "old");
- newVal = _db.HashGet(key, "new");
- }
-
- // Se uno dei due manca, impostalo al default (non sovrascrive l'altro)
- if (oldVal.IsNull)
- {
- _db.HashSet(key, "old", _defaultOld, When.NotExists);
- oldVal = _defaultOld;
- }
- if (newVal.IsNull)
- {
- _db.HashSet(key, "new", _defaultNew, When.NotExists);
- newVal = _defaultNew;
- }
-
- if (!int.TryParse(oldVal.ToString(), out var oldW)) oldW = _defaultOld;
- if (!int.TryParse(newVal.ToString(), out var newW)) newW = _defaultNew;
-
- // clamp 0..100
- oldW = Math.Clamp(oldW, 0, 100);
- newW = Math.Clamp(newW, 0, 100);
-
- return (oldW, newW);
- }
-
- // API per aggiornare i pesi a runtime (opzionale)
- public void SetWeights(string method, int oldWeight, int newWeight)
- {
- var key = _keyPrefix + (string.IsNullOrEmpty(method) ? "unknown" : method);
- _db.HashSet(key, new HashEntry[] {
- new HashEntry("old", Math.Clamp(oldWeight,0,100)),
- new HashEntry("new", Math.Clamp(newWeight,0,100))
- });
- }
-
- public async Task> GetAllWeightsAsync()
- {
- var result = new List();
- var server = _mux.GetServer(_mux.GetEndPoints().First());
-
- if (server.IsReplica)
- {
- return result;
- }
-
- await foreach (var key in server.KeysAsync(pattern: $"{_keyPrefix}*"))
- {
- var methodName = KeyToString(key.ToString());
- if (string.IsNullOrEmpty(methodName)) continue;
-
- var oldVal = _db.HashGet(key, "old");
- var newVal = _db.HashGet(key, "new");
-
- int oldW = 100;
- int newW = 0;
-
- if (!oldVal.IsNull && int.TryParse(oldVal.ToString(), out var parsedOld))
- oldW = Math.Clamp(parsedOld, 0, 100);
-
- if (!newVal.IsNull && int.TryParse(newVal.ToString(), out var parsedNew))
- newW = Math.Clamp(parsedNew, 0, 100);
-
- result.Add(new WeightDTO { Method = methodName, OldWeight = oldW, NewWeight = newW });
- }
-
- // riordino desc x NEW poi alfabetico...
- result = result
- .OrderByDescending(x => x.NewWeight)
- .ThenBy(x => x.Method)
- .ToList();
-
- return result;
- }
-
- public bool UpsertWeight(WeightDTO updRecord)
- {
- if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
- return false;
-
- var key = _keyPrefix + updRecord.Method;
- _db.HashSet(key, new HashEntry[] {
- new HashEntry("old", Math.Clamp(updRecord.OldWeight, 0, 100)),
- new HashEntry("new", Math.Clamp(updRecord.NewWeight, 0, 100))
- });
-
- return true;
- }
-
- private string KeyToString(string key)
- {
- if (string.IsNullOrEmpty(key)) return "";
- var prefix = _keyPrefix ?? "";
- if (key.StartsWith(prefix))
- return key.Substring(prefix.Length);
- return key;
- }
-
- #endregion Public Methods
-
- #region Private Fields
-
- private static string _keyPrefix = "route_weight:";
- private static string _redisBaseKey = "";
- private readonly IConfiguration _config;
- private readonly IDatabase _db;
- private readonly IConnectionMultiplexer _mux;
- private readonly int _defaultNew;
- private readonly int _defaultOld;
-
- #endregion Private Fields
- }
-}
diff --git a/MP.RIOC/Services/RouteManager.cs b/MP.RIOC/Services/RouteManager.cs
index ce661fd0..fb1f2865 100644
--- a/MP.RIOC/Services/RouteManager.cs
+++ b/MP.RIOC/Services/RouteManager.cs
@@ -1,4 +1,5 @@
-using NLog;
+using MP.Data.Services.RouteWeight;
+using NLog;
using System.Diagnostics;
using Yarp.ReverseProxy.Forwarder;
diff --git a/MP.RIOC/appsettings.Development.json b/MP.RIOC/appsettings.Development.json
index d7f9ed43..4e4724a3 100644
--- a/MP.RIOC/appsettings.Development.json
+++ b/MP.RIOC/appsettings.Development.json
@@ -3,7 +3,8 @@
"LogLevel": {
"Default": "Information",
"Yarp": "Warning",
- "Microsoft.AspNetCore": "Warning"
+ "Microsoft.AspNetCore": "Warning",
+ "FusionCache": "Warning"
}
}
}
diff --git a/MP.RIOC/appsettings.Production.json b/MP.RIOC/appsettings.Production.json
index 7910e3ea..befdd501 100644
--- a/MP.RIOC/appsettings.Production.json
+++ b/MP.RIOC/appsettings.Production.json
@@ -3,7 +3,8 @@
"LogLevel": {
"Default": "Information",
"Yarp": "Warning",
- "Microsoft.AspNetCore": "Warning"
+ "Microsoft.AspNetCore": "Warning",
+ "FusionCache": "Warning"
}
},
"AllowedHosts": "*",
diff --git a/MP.RIOC/appsettings.Staging-silent.json b/MP.RIOC/appsettings.Staging-silent.json
index b68fbaa1..8332e76c 100644
--- a/MP.RIOC/appsettings.Staging-silent.json
+++ b/MP.RIOC/appsettings.Staging-silent.json
@@ -5,11 +5,17 @@
"Yarp": "Warning",
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
- "Microsoft.AspNetCore.Hosting.Diagnostics": "Warning"
+ "Microsoft.AspNetCore.Hosting.Diagnostics": "Warning",
+ "FusionCache": "Warning"
}
},
"NLog": {
"rules": [
+ {
+ "logger": "FusionCache",
+ "maxLevel": "Info",
+ "final": true
+ },
{
"logger": "Microsoft.*",
"maxLevel": "Fatal",
diff --git a/MP.RIOC/appsettings.Staging-verbose.json b/MP.RIOC/appsettings.Staging-verbose.json
index cdb99149..5865f347 100644
--- a/MP.RIOC/appsettings.Staging-verbose.json
+++ b/MP.RIOC/appsettings.Staging-verbose.json
@@ -4,7 +4,8 @@
"Default": "Warning",
"Yarp": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
- "Microsoft.AspNetCore.Hosting.Diagnostics": "Information"
+ "Microsoft.AspNetCore.Hosting.Diagnostics": "Information",
+ "FusionCache": "Warning"
}
},
"NLog": {
diff --git a/MP.RIOC/appsettings.Staging.json b/MP.RIOC/appsettings.Staging.json
index b68fbaa1..8332e76c 100644
--- a/MP.RIOC/appsettings.Staging.json
+++ b/MP.RIOC/appsettings.Staging.json
@@ -5,11 +5,17 @@
"Yarp": "Warning",
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
- "Microsoft.AspNetCore.Hosting.Diagnostics": "Warning"
+ "Microsoft.AspNetCore.Hosting.Diagnostics": "Warning",
+ "FusionCache": "Warning"
}
},
"NLog": {
"rules": [
+ {
+ "logger": "FusionCache",
+ "maxLevel": "Info",
+ "final": true
+ },
{
"logger": "Microsoft.*",
"maxLevel": "Fatal",
diff --git a/MP.RIOC/appsettings.json b/MP.RIOC/appsettings.json
index 809c089c..2522b6f6 100644
--- a/MP.RIOC/appsettings.json
+++ b/MP.RIOC/appsettings.json
@@ -6,7 +6,8 @@
"Microsoft.AspNetCore.Hosting.Diagnostics": "Information",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
- "Microsoft.AspNetCore": "Warning"
+ "Microsoft.AspNetCore": "Warning",
+ "FusionCache": "Warning"
}
},
"AllowedHosts": "*",
@@ -40,6 +41,11 @@
}
},
"rules": [
+ {
+ "logger": "FusionCache*",
+ "maxLevel": "Info",
+ "final": true
+ },
{
"logger": "Microsoft.EntityFrameworkCore.*",
"maxLevel": "Info",
diff --git a/MP.SPEC/MP.SPEC.csproj b/MP.SPEC/MP.SPEC.csproj
index 906a6c6d..628337bc 100644
--- a/MP.SPEC/MP.SPEC.csproj
+++ b/MP.SPEC/MP.SPEC.csproj
@@ -5,7 +5,7 @@
enable
enable
MP.SPEC
- 8.16.2606.1312
+ 8.16.2606.2208
1800a78a-6ff1-40f9-b490-87fb8bfc1394
en
diff --git a/MP.SPEC/Resources/ChangeLog.html b/MP.SPEC/Resources/ChangeLog.html
index b09252cc..5711f4d3 100644
--- a/MP.SPEC/Resources/ChangeLog.html
+++ b/MP.SPEC/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MAPOSPEC
- Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
-
diff --git a/MP.SPEC/Resources/VersNum.txt b/MP.SPEC/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.SPEC/Resources/VersNum.txt
+++ b/MP.SPEC/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.SPEC/Resources/manifest.xml b/MP.SPEC/Resources/manifest.xml
index ed5dece3..1b142fab 100644
--- a/MP.SPEC/Resources/manifest.xml
+++ b/MP.SPEC/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/MP.SPEC.zip
https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/ChangeLog.html
false
diff --git a/MP.Stats/MP.Stats.csproj b/MP.Stats/MP.Stats.csproj
index d203eefb..1614299a 100644
--- a/MP.Stats/MP.Stats.csproj
+++ b/MP.Stats/MP.Stats.csproj
@@ -4,7 +4,7 @@
net8.0
MP.Stats
826e877c-ba70-4253-84cb-d0b1cafd4440
- 8.16.2606.1312
+ 8.16.2606.2208
true
en
diff --git a/MP.Stats/Resources/ChangeLog.html b/MP.Stats/Resources/ChangeLog.html
index ef9a814f..947d141b 100644
--- a/MP.Stats/Resources/ChangeLog.html
+++ b/MP.Stats/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo statistiche MAPO
-
Versione: 8.16.2606.1312
+ Versione: 8.16.2606.2208
Note di rilascio:
diff --git a/MP.Stats/Resources/VersNum.txt b/MP.Stats/Resources/VersNum.txt
index 84233792..60d2cec2 100644
--- a/MP.Stats/Resources/VersNum.txt
+++ b/MP.Stats/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.2208
diff --git a/MP.Stats/Resources/manifest.xml b/MP.Stats/Resources/manifest.xml
index 4401e30e..9e65b1b9 100644
--- a/MP.Stats/Resources/manifest.xml
+++ b/MP.Stats/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.2208
https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/MP.Stats.zip
https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/ChangeLog.html
false