Spostasmento RouteWeight in servizi condivisi...
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP_TAB3</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MAPOSPEC </i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/MP-TAB3.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
+4
-2
@@ -1,6 +1,8 @@
|
||||
using MP.Core.DTO;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MP.RIOC.Services
|
||||
namespace MP.Data.Services.RouteWeight
|
||||
{
|
||||
public interface IWeightProvider
|
||||
{
|
||||
@@ -26,4 +28,4 @@ namespace MP.RIOC.Services
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-15
@@ -1,13 +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.RIOC.Services
|
||||
namespace MP.Data.Services.RouteWeight
|
||||
{
|
||||
public class InMemoryWeightProvider : IWeightProvider
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, (int oldW, int newW)> _map = new();
|
||||
private readonly int _defaultOld;
|
||||
private readonly int _defaultNew;
|
||||
#region Public Constructors
|
||||
|
||||
public InMemoryWeightProvider(IConfiguration config)
|
||||
{
|
||||
@@ -15,16 +17,9 @@ namespace MP.RIOC.Services
|
||||
_defaultNew = config.GetValue<int>("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<List<WeightDTO>> GetAllWeightsAsync()
|
||||
{
|
||||
@@ -43,6 +38,17 @@ namespace MP.RIOC.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))
|
||||
@@ -52,5 +58,15 @@ namespace MP.RIOC.Services
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private readonly int _defaultNew;
|
||||
private readonly int _defaultOld;
|
||||
private readonly ConcurrentDictionary<string, (int oldW, int newW)> _map = new();
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-5
@@ -1,8 +1,13 @@
|
||||
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.RIOC.Services
|
||||
namespace MP.Data.Services.RouteWeight
|
||||
{
|
||||
public class RedisWeightProvider : IWeightProvider
|
||||
{
|
||||
@@ -36,7 +41,6 @@ namespace MP.RIOC.Services
|
||||
if (string.IsNullOrEmpty(method)) return;
|
||||
|
||||
var cacheKey = $"weights:{method}";
|
||||
|
||||
// Rimuove la chiave dalla RAM (L1) dell'istanza corrente del Gateway
|
||||
_cache.Remove(cacheKey);
|
||||
}
|
||||
@@ -174,7 +178,7 @@ namespace MP.RIOC.Services
|
||||
new HashEntry("new", Math.Clamp(newWeight,0,100))
|
||||
});
|
||||
|
||||
// 2. 🚀 COORDINAZIONE: Rimuovi la chiave da FusionCache.
|
||||
// 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);
|
||||
@@ -192,7 +196,7 @@ namespace MP.RIOC.Services
|
||||
new HashEntry("new", Math.Clamp(updRecord.NewWeight, 0, 100))
|
||||
});
|
||||
|
||||
// 2. 🚀 COORDINAZIONE: Rimuovi la chiave da FusionCache.
|
||||
// 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);
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP.INVE</RootNamespace>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MAPOINVE </i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/MP.INVE.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Services\BaseServ.cs" />
|
||||
<Compile Remove="Services\InMemoryWeightProvider.cs" />
|
||||
<Compile Remove="Services\IWeightProvider.cs" />
|
||||
<Compile Remove="Services\RedisWeightProvider.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="compilerconfig.json" />
|
||||
</ItemGroup>
|
||||
@@ -57,6 +64,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Components\Layout\" />
|
||||
<Folder Include="Services\" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
+1
-4
@@ -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;
|
||||
@@ -124,9 +124,6 @@ builder.Services.AddFusionCache()
|
||||
// Jitter: variazione casuale alla scadenza per evitare scadenze in blocco
|
||||
options.JitterMaxDuration = TimeSpan.FromSeconds(5);
|
||||
});
|
||||
//// 3. LA RIGA MAGICA: Estrae l'istanza nominata e la mappa come IFusionCache standard
|
||||
//builder.Services.AddSingleton<IFusionCache>(sp =>
|
||||
// sp.GetRequiredService<IFusionCacheProvider>().GetCache("MAPO_MES_FusionCache"));
|
||||
|
||||
// aggiunta http client x chiamare REST esterne (reset cache su RIOC, in attesa fix fusionCache)
|
||||
builder.Services.AddHttpClient();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MP-IOC </i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public class BaseServ
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Inizializza una nuova istanza della classe BaseServ.
|
||||
/// Configura la connessione Redis, carica le impostazioni di configurazione e inizializza il serializzatore JSON.
|
||||
/// </summary>
|
||||
/// <param name="Configuration">Oggetto di configurazione per recuperare le impostazioni dell'applicazione.</param>
|
||||
/// <param name="RedisConn">Multiplexer di connessione Redis per operazioni sul database.</param>
|
||||
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<string>("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
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per la comunicazione riguardo update calcolo BOM
|
||||
/// </summary>
|
||||
public MessagePipe PipeBom { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno HwList da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelHwList.
|
||||
/// </summary>
|
||||
public MessagePipe PipeHwList { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno HwOptions calcolate da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelHwOpt.
|
||||
/// </summary>
|
||||
public MessagePipe PipeHwOpt { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno PNG calcolati da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelPng.
|
||||
/// </summary>
|
||||
public MessagePipe PipePng { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Canale informazioni relativo ad attività relative alla gesitone PROD:
|
||||
/// - carico macchine
|
||||
/// - scheduling
|
||||
/// </summary>
|
||||
public MessagePipe PipeProd { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno info elementi del profile
|
||||
/// </summary>
|
||||
public MessagePipe PipeProfElement { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno ProfileListAsync calcolate da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelProfList.
|
||||
/// </summary>
|
||||
public MessagePipe PipeProfList { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno Shape calcolate da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelShape.
|
||||
/// </summary>
|
||||
public MessagePipe PipeShape { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno SVG calcolati da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelSvg.
|
||||
/// </summary>
|
||||
public MessagePipe PipeSvg { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per la comunicazione riguardo update generico UI
|
||||
/// </summary>
|
||||
public MessagePipe PipeUpdate { get; set; } = null!;
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto per collezione dati Activity (span in Uptrace)
|
||||
/// </summary>
|
||||
protected static readonly ActivitySource ActivitySource = new ActivitySource("Lux.DATA");
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
protected static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto di configurazione statico per accedere alle impostazioni dell'applicazione (es. stringhe di connessione).
|
||||
/// Condiviso tra tutte le istanze di BaseServ.
|
||||
/// </summary>
|
||||
protected readonly IConfiguration _config = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Path base chiavi REDIS
|
||||
/// </summary>
|
||||
protected readonly string _redisBaseKey = "Lux:Cache";
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto per la connessione a Redis utilizzato per operazioni di lettura/scrittura.
|
||||
/// </summary>
|
||||
protected readonly IConnectionMultiplexer _redisConn = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Database Redis utilizzato per le operazioni di lettura/scrittura
|
||||
/// nb: ottenuto tramite _redisConn.GetDatabase()
|
||||
/// </summary>
|
||||
protected readonly IDatabase _redisDb = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Abilitazione operazioni tracing generiche
|
||||
/// </summary>
|
||||
protected readonly bool _traceEnabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// Impostazioni del serializzatore JSON utilizzato per gestire oggetti con riferimenti circolari
|
||||
/// (es. oggetti che si fanno riferimento reciprocamente).
|
||||
/// </summary>
|
||||
protected JsonSerializerSettings? JSSettings;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache breve (circa 1 minuto + variazione del +/-10%)
|
||||
/// </summary>
|
||||
protected TimeSpan FastCache
|
||||
{
|
||||
get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache lunga (+ variazione del +/-10%)
|
||||
/// </summary>
|
||||
protected TimeSpan LongCache
|
||||
{
|
||||
get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache molto breve (circa 10 secondi + variazione del +/-10%)
|
||||
/// </summary>
|
||||
protected TimeSpan UltraFastCache
|
||||
{
|
||||
get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache molto lunga (+ variazione del +/-10%)
|
||||
/// </summary>
|
||||
protected TimeSpan UltraLongCache
|
||||
{
|
||||
get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000);
|
||||
}
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Helper avvio attività per la funzione tracciata
|
||||
/// </summary>
|
||||
/// <param name="methodName"></param>
|
||||
/// <returns></returns>
|
||||
protected static Activity? StartActivity([CallerMemberName] string? methodName = null)
|
||||
{
|
||||
var activity = ActivitySource.StartActivity(methodName ?? "UNDEF");
|
||||
activity?.SetTag("host.name", Environment.MachineName);
|
||||
return activity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalida una o più chiavi/pattern in Redis
|
||||
/// </summary>
|
||||
protected async Task ClearCacheAsync(params string[] patterns)
|
||||
{
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
// Chiamata al tuo metodo esistente
|
||||
await ExecFlushRedisPatternAsync((RedisValue)pattern);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Metodo di flush dati cache Redis
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper generale di lettura da cache o da funzione (DB) con caching successivo
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="expiration"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<T> GetOrSetCacheAsync<T>(string key, Func<Task<T>> 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<T>(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!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper trace messaggio log (SE abilitato)
|
||||
/// </summary>
|
||||
/// <param name="traceMsg"></param>
|
||||
/// <param name="reqLevel"></param>
|
||||
/// <param name="methodName"></param>
|
||||
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}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper generale per la telemetria e gestione eccezioni
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="body"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<T> TraceAsync<T>(string name, Func<Activity?, Task<T>> 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<string, SemaphoreSlim> _locks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
private int cacheTtlLong = 60 * 5;
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache breve in secondi (predefinito: 1 minuto)
|
||||
/// Utilizzato nelle proprietà FastCache e UltraFastCache per definire la durata della cache breve.
|
||||
/// </summary>
|
||||
private int cacheTtlShort = 60 * 1;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
private Random rnd = new Random();
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using MP.Core.DTO;
|
||||
|
||||
namespace MP.IOC.Services
|
||||
{
|
||||
public interface IWeightProvider
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Ritorna l'intero elenco dei weight attivi nel formato WeightDTO
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<WeightDTO>> GetAllWeightsAsync();
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Ritorna la coppia (oldWeight, newWeight) per scegliere dove instradare il metodo tra i 2 sistemi API.
|
||||
/// </summary>
|
||||
(int oldWeight, int newWeight) GetWeightsFor(string method);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna/Aggiuinge il valore del weight richiesto
|
||||
/// </summary>
|
||||
/// <param name=""></param>
|
||||
/// <returns></returns>
|
||||
bool UpsertWeight(WeightDTO updRecord);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using MP.Core.DTO;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace MP.IOC.Services
|
||||
{
|
||||
|
||||
public class InMemoryWeightProvider : IWeightProvider
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, (int oldW, int newW)> _map = new();
|
||||
private readonly int _defaultOld;
|
||||
private readonly int _defaultNew;
|
||||
|
||||
public InMemoryWeightProvider(IConfiguration config)
|
||||
{
|
||||
_defaultOld = config.GetValue<int>("RouteMan:DefaultWeightOld", 100);
|
||||
_defaultNew = config.GetValue<int>("RouteMan:DefaultWeightNew", 0);
|
||||
}
|
||||
|
||||
#if false
|
||||
public (int oldWeight, int newWeight) GetWeightsFor(string method)
|
||||
{
|
||||
if (string.IsNullOrEmpty(method)) method = "unknown";
|
||||
return _map.GetOrAdd(method, _ => (_defaultOld, _defaultNew));
|
||||
}
|
||||
#endif
|
||||
|
||||
public void SetWeights(string method, int oldWeight, int newWeight)
|
||||
{
|
||||
_map[method] = (Math.Clamp(oldWeight, 0, 100), Math.Clamp(newWeight, 0, 100));
|
||||
}
|
||||
|
||||
public async Task<List<WeightDTO>> GetAllWeightsAsync()
|
||||
{
|
||||
var result = new List<WeightDTO>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
using MP.Core.DTO;
|
||||
using NLog;
|
||||
using StackExchange.Redis;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace MP.IOC.Services
|
||||
{
|
||||
public class RedisWeightProvider : IWeightProvider
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public RedisWeightProvider(
|
||||
IConnectionMultiplexer mux,
|
||||
IFusionCache cache,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IConfiguration config)
|
||||
{
|
||||
_cache = cache;
|
||||
_config = config;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_db = mux.GetDatabase();
|
||||
_mux = mux;
|
||||
_defaultOld = config.GetValue<int>("RouteMan:DefaultWeightOld", 100);
|
||||
_defaultNew = config.GetValue<int>("RouteMan:DefaultWeightNew", 0);
|
||||
_redisBaseKey = config.GetValue<string>("ServerConf:RedisBaseKey") ?? "MP_IOC";
|
||||
// Leggiamo l'URL base del gateway dal file di configurazione dell'Admin
|
||||
// es. "https://10.74.83.100:5290/MP/RIOC/api/admin/cache/purge-route/"
|
||||
_gatewayPurgeUrl = config.GetValue<string>("ServerConf:GatewayPurgeUrl") ?? "https://localhost:7120/MP/RIOC/api/admin/cache/purge-route/";
|
||||
_keyPrefix = $"{_redisBaseKey}:route_weight:";
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<WeightDTO>> GetAllWeightsAsync()
|
||||
{
|
||||
var result = new List<WeightDTO>();
|
||||
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;
|
||||
}
|
||||
|
||||
// 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))
|
||||
});
|
||||
|
||||
ResetFusionCache(method);
|
||||
}
|
||||
|
||||
public bool UpsertWeight(WeightDTO updRecord)
|
||||
{
|
||||
if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
|
||||
return false;
|
||||
|
||||
// 1. Scrivi su Redis (Sorgente dati reale)
|
||||
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))
|
||||
});
|
||||
|
||||
ResetFusionCache(updRecord.Method);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private static string _keyPrefix = "route_weight:";
|
||||
private static string _redisBaseKey = "";
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private readonly IFusionCache _cache;
|
||||
private readonly IConfiguration _config;
|
||||
private readonly IDatabase _db;
|
||||
private readonly int _defaultNew;
|
||||
private readonly int _defaultOld;
|
||||
private readonly string _gatewayPurgeUrl;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IConnectionMultiplexer _mux;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private string KeyToString(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return "";
|
||||
var prefix = _keyPrefix ?? "";
|
||||
if (key.StartsWith(prefix))
|
||||
return key.Substring(prefix.Length);
|
||||
return key;
|
||||
}
|
||||
|
||||
private void ResetFusionCache(string method)
|
||||
{
|
||||
//try
|
||||
//{
|
||||
// // Sfrutta la factory per prendere un client ottimizzato e pulito
|
||||
// using var client = _httpClientFactory.CreateClient();
|
||||
|
||||
// // Componiamo l'URL finale pulito (es. .../purge-route/SIMUL_01)
|
||||
// var finalUrl = $"{_gatewayPurgeUrl.TrimEnd('/')}/{updRecord.Method}";
|
||||
|
||||
// // Inviamo la POST (passiamo null come HttpContent perché non serve un Body)
|
||||
// var response = client.PostAsync(finalUrl, null);
|
||||
|
||||
// if (response.IsSuccessStatusCode)
|
||||
// {
|
||||
// Log.Info($"[CACHE] Sfratto RAM notificato con successo al Gateway per il metodo: {updRecord.Method}");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Log.Warn($"[CACHE] Il gateway ha risposto con codice {response.StatusCode} alla purga di {updRecord.Method}");
|
||||
// }
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// // Usiamo un log di errore ma non blocchiamo l'applicazione Admin
|
||||
// // se il gateway in quel momento fosse offline o irraggiungibile
|
||||
// Log.Error(ex, $"[CACHE] Impossibile raggiungere il gateway per spurgare la rotta: {updRecord.Method}");
|
||||
//}
|
||||
|
||||
// Grazie al Backplane Pub/Sub, la RAM verrà azzerata istantaneamente su TUTTI i server.
|
||||
var cacheKey = $"weights:{method}";
|
||||
_cache.Remove(cacheKey);
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Ritorna (oldWeight, newWeight) per il metodo. Se non esiste, crea la chiave con i default.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>MP.Land</RootNamespace>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
<Configurations>Debug;Release;Debug_LiManDebug</Configurations>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo Tablet MAPO - DotNet6</i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br />
|
||||
Note di rilascio:
|
||||
<ul>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/MP.Land.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP.MON</RootNamespace>
|
||||
<AssemblyName>$(AssemblyName.Replace(' ', '_'))</AssemblyName>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MAPOSPEC </i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/MP.MON.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>MP.Prog</RootNamespace>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo gestione Programmi MAPO</i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br />
|
||||
Note di rilascio:
|
||||
<ul>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/MP.Prog.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -5,10 +5,16 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP.RIOC</RootNamespace>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Services\InMemoryWeightProvider.cs" />
|
||||
<Compile Remove="Services\IWeightProvider.cs" />
|
||||
<Compile Remove="Services\RedisWeightProvider.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="compilerconfig.json" />
|
||||
</ItemGroup>
|
||||
|
||||
+1
-3
@@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
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;
|
||||
@@ -118,9 +119,6 @@ builder.Services.AddFusionCache()
|
||||
// Jitter: variazione casuale alla scadenza per evitare scadenze in blocco
|
||||
options.JitterMaxDuration = TimeSpan.FromSeconds(5);
|
||||
});
|
||||
//// 3. LA RIGA MAGICA: Estrae l'istanza nominata e la mappa come IFusionCache standard
|
||||
//builder.Services.AddSingleton<IFusionCache>(sp =>
|
||||
// sp.GetRequiredService<IFusionCacheProvider>().GetCache("MAPO_MES_FusionCache"));
|
||||
|
||||
// Registrazione dei servizi custom
|
||||
builder.Services.AddSingleton<PreserveBodyTransformer>();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MP-RIOC </i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/MP.RIOC.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using NLog;
|
||||
using MP.Data.Services.RouteWeight;
|
||||
using NLog;
|
||||
using System.Diagnostics;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP.SPEC</RootNamespace>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
<UserSecretsId>1800a78a-6ff1-40f9-b490-87fb8bfc1394</UserSecretsId>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MAPOSPEC </i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/MP.SPEC.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>MP.Stats</RootNamespace>
|
||||
<UserSecretsId>826e877c-ba70-4253-84cb-d0b1cafd4440</UserSecretsId>
|
||||
<Version>8.16.2606.2013</Version>
|
||||
<Version>8.16.2606.2208</Version>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo statistiche MAPO</i>
|
||||
<h4>Versione: 8.16.2606.2013</h4>
|
||||
<h4>Versione: 8.16.2606.2208</h4>
|
||||
<br />
|
||||
Note di rilascio:
|
||||
<ul>
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.16.2606.2013
|
||||
8.16.2606.2208
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>8.16.2606.2013</version>
|
||||
<version>8.16.2606.2208</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/MP.Stats.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user