Update gestione script LUA:
- cartella con script - conf x scelta - gestione script letti 1 sola volta all'avvio
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace MP.Core.Conf
|
||||
{
|
||||
public class RedisScriptsConfig
|
||||
{
|
||||
public Dictionary<string, string> Scripts { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>6.16.2604.2008</Version>
|
||||
<Version>6.16.2604.2010</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -48,6 +48,12 @@
|
||||
<None Update="post-build.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="RedisScript\RedisUpdateScript_v5.lua">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="RedisScript\RedisUpdateScript_v6.lua">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using MP.Core.Conf;
|
||||
using MP.Data;
|
||||
using MP.Data.Repository.Utils;
|
||||
using MP.Data.Services.Utils;
|
||||
@@ -59,11 +60,16 @@ builder.Services.AddSingleton(sp =>
|
||||
});
|
||||
logger.Info("YARP reverse proxy configured");
|
||||
|
||||
builder.Services.Configure<RedisScriptsConfig>(
|
||||
builder.Configuration.GetSection("RedisScripts"));
|
||||
logger.Info("RedisScript Provider configured");
|
||||
|
||||
// base services
|
||||
builder.Services.AddSingleton<PreserveBodyTransformer>();
|
||||
builder.Services.AddSingleton<RouteStatsManager>();
|
||||
builder.Services.AddHostedService<MetricsCalcService>();
|
||||
builder.Services.AddHostedService<MetricsDbFlushService>();
|
||||
builder.Services.AddSingleton<LuaScriptProvider>();
|
||||
|
||||
// Registra i servizi per Blazor
|
||||
builder.Services.AddRazorComponents()
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
-- RedisUpdateScript_v5
|
||||
local key = KEYS[1]
|
||||
local countInc = tonumber(ARGV[1]) or 0
|
||||
local totalMsInc = tonumber(ARGV[2]) or 0
|
||||
local newMax = tonumber(ARGV[3])
|
||||
local newMin = tonumber(ARGV[4])
|
||||
local sentinel = tonumber(ARGV[5])
|
||||
|
||||
-- Incrementi base
|
||||
redis.call('HINCRBY', key, 'count', countInc)
|
||||
redis.call('HINCRBYFLOAT', key, 'totalMs', totalMsInc)
|
||||
|
||||
-- MAX
|
||||
local currentMaxStr = redis.call('HGET', key, 'maxMs')
|
||||
local currentMax = tonumber(currentMaxStr)
|
||||
|
||||
if newMax ~= nil and newMax < sentinel then
|
||||
if currentMax == nil or newMax > currentMax then
|
||||
redis.call('HSET', key, 'maxMs', newMax)
|
||||
end
|
||||
end
|
||||
|
||||
-- MIN
|
||||
local currentMinStr = redis.call('HGET', key, 'minMs')
|
||||
local currentMin = tonumber(currentMinStr)
|
||||
|
||||
if newMin ~= nil and newMin < sentinel then
|
||||
if currentMin == nil or newMin < currentMin then
|
||||
redis.call('HSET', key, 'minMs', newMin)
|
||||
end
|
||||
end
|
||||
|
||||
return 1
|
||||
@@ -0,0 +1,33 @@
|
||||
-- RedisUpdateScript_v6
|
||||
local key = KEYS[1]
|
||||
local countInc = tonumber(ARGV[1]) or 0
|
||||
local totalMsInc = tonumber(ARGV[2]) or 0
|
||||
local newMax = tonumber(ARGV[3])
|
||||
local newMin = tonumber(ARGV[4])
|
||||
local sentinel = tonumber(ARGV[5])
|
||||
|
||||
-- Incrementi
|
||||
redis.call('HINCRBY', key, 'count', countInc)
|
||||
redis.call('HINCRBYFLOAT', key, 'totalMs', totalMsInc)
|
||||
|
||||
-- MAX
|
||||
local currentMaxStr = redis.call('HGET', key, 'maxMs')
|
||||
local currentMax = tonumber(currentMaxStr)
|
||||
|
||||
if newMax ~= nil and newMax < sentinel then
|
||||
if currentMax == nil or newMax > currentMax then
|
||||
redis.call('HSET', key, 'maxMs', tostring(newMax))
|
||||
end
|
||||
end
|
||||
|
||||
-- MIN
|
||||
local currentMinStr = redis.call('HGET', key, 'minMs')
|
||||
local currentMin = tonumber(currentMinStr)
|
||||
|
||||
if newMin ~= nil and newMin < sentinel then
|
||||
if currentMin == nil or newMin < currentMin then
|
||||
redis.call('HSET', key, 'minMs', tostring(newMin))
|
||||
end
|
||||
end
|
||||
|
||||
return 1
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MP-IOC </i>
|
||||
<h4>Versione: 6.16.2604.2008</h4>
|
||||
<h4>Versione: 6.16.2604.2010</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.16.2604.2008
|
||||
6.16.2604.2010
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>6.16.2604.2008</version>
|
||||
<version>6.16.2604.2010</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>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using MP.Core.Conf;
|
||||
|
||||
namespace MP.IOC.Services
|
||||
{
|
||||
public sealed class LuaScriptProvider
|
||||
{
|
||||
private readonly Dictionary<string, string> _scripts;
|
||||
|
||||
public IReadOnlyDictionary<string, string> Scripts => _scripts;
|
||||
|
||||
public LuaScriptProvider(
|
||||
IOptions<RedisScriptsConfig> cfg,
|
||||
IWebHostEnvironment env)
|
||||
{
|
||||
_scripts = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var kv in cfg.Value.Scripts)
|
||||
{
|
||||
var name = kv.Key;
|
||||
var relativePath = kv.Value;
|
||||
|
||||
var fullPath = Path.Combine(env.ContentRootPath, relativePath);
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
throw new FileNotFoundException($"Script Lua non trovato: {fullPath}");
|
||||
|
||||
var content = File.ReadAllText(fullPath);
|
||||
|
||||
_scripts[name] = content;
|
||||
}
|
||||
}
|
||||
|
||||
public string Get(string name)
|
||||
{
|
||||
if (!_scripts.TryGetValue(name, out var script))
|
||||
throw new KeyNotFoundException($"Script Lua '{name}' non trovato.");
|
||||
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,12 +14,16 @@ namespace MP.IOC.Services
|
||||
/// <param name="stats"></param>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="mux"></param>
|
||||
public MetricsCalcService(RouteStatsManager stats, IConfiguration config, IConnectionMultiplexer mux)
|
||||
public MetricsCalcService(RouteStatsManager stats,
|
||||
LuaScriptProvider luaProvider,
|
||||
IConfiguration config,
|
||||
IConnectionMultiplexer mux)
|
||||
{
|
||||
_stats = stats;
|
||||
_config = config;
|
||||
_db = mux.GetDatabase();
|
||||
_redisBaseKey = _config.GetValue<string>("ServerConf:RedisBaseKey") ?? "MP_IOC";
|
||||
_updateScript = luaProvider.Get("Update");
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
@@ -33,11 +37,18 @@ namespace MP.IOC.Services
|
||||
/// </summary>
|
||||
private const string SentinelValue = "999999999";
|
||||
|
||||
/// <summary>
|
||||
/// Script update Redis in Lua, recuperato dal provider script.
|
||||
/// Lo script gestisce l'incremento e la logica condizionale per Min/Max in un'unica operazione atomica.
|
||||
/// </summary>
|
||||
private readonly string _updateScript;
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Script update Redis in Lua, definito come costante per efficienza.
|
||||
/// Lo script gestisce l'incremento e la logica condizionale per Min/Max in un'unica operazione atomica.
|
||||
/// </summary>
|
||||
private const string RedisUpdateScript = @"
|
||||
private const string RedisUpdateScript_v6 = @"
|
||||
local key = KEYS[1]
|
||||
local countInc = tonumber(ARGV[1])
|
||||
local totalMsInc = tonumber(ARGV[2])
|
||||
@@ -63,6 +74,45 @@ namespace MP.IOC.Services
|
||||
return 1
|
||||
";
|
||||
|
||||
|
||||
private const string RedisUpdateScript_v5 = @"
|
||||
local key = KEYS[1]
|
||||
local countInc = tonumber(ARGV[1]) or 0
|
||||
local totalMsInc = tonumber(ARGV[2]) or 0
|
||||
local newMax = tonumber(ARGV[3])
|
||||
local newMin = tonumber(ARGV[4])
|
||||
local sentinel = tonumber(ARGV[5])
|
||||
|
||||
-- Incrementi base
|
||||
redis.call('HINCRBY', key, 'count', countInc)
|
||||
redis.call('HINCRBYFLOAT', key, 'totalMs', totalMsInc)
|
||||
|
||||
-- MAX
|
||||
local currentMaxStr = redis.call('HGET', key, 'maxMs')
|
||||
local currentMax = tonumber(currentMaxStr)
|
||||
|
||||
if newMax ~= nil and newMax < sentinel then
|
||||
if currentMax == nil or newMax > currentMax then
|
||||
redis.call('HSET', key, 'maxMs', newMax)
|
||||
end
|
||||
end
|
||||
|
||||
-- MIN
|
||||
local currentMinStr = redis.call('HGET', key, 'minMs')
|
||||
local currentMin = tonumber(currentMinStr)
|
||||
|
||||
if newMin ~= nil and newMin < sentinel then
|
||||
if currentMin == nil or newMin < currentMin then
|
||||
redis.call('HSET', key, 'minMs', newMin)
|
||||
end
|
||||
end
|
||||
|
||||
return 1
|
||||
|
||||
";
|
||||
#endif
|
||||
|
||||
|
||||
// Classe di supporto per l'aggregazione locale dei valori Daily
|
||||
private class AggregatedStats
|
||||
{
|
||||
@@ -124,7 +174,7 @@ namespace MP.IOC.Services
|
||||
var hourScore = ToEpochSeconds(hourStart);
|
||||
|
||||
// Usiamo lo script Lua per l'aggiornamento atomico dell'ora
|
||||
tasks.Add(batch.ScriptEvaluateAsync(RedisUpdateScript,
|
||||
tasks.Add(batch.ScriptEvaluateAsync(_updateScript,
|
||||
new RedisKey[] { hourKey },
|
||||
new RedisValue[] {
|
||||
count.ToString(),
|
||||
@@ -167,7 +217,7 @@ namespace MP.IOC.Services
|
||||
? double.Parse(SentinelValue)
|
||||
: agg.MinMs;
|
||||
|
||||
tasks.Add(batch.ScriptEvaluateAsync(RedisUpdateScript,
|
||||
tasks.Add(batch.ScriptEvaluateAsync(_updateScript,
|
||||
new RedisKey[] { key },
|
||||
new RedisValue[] {
|
||||
agg.Count.ToString(),
|
||||
|
||||
@@ -31,5 +31,10 @@
|
||||
"Redis": "localhost:6379,DefaultDatabase=5,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false",
|
||||
"RedisAdmin": "localhost:6379,DefaultDatabase=5,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,allowAdmin=true",
|
||||
"mdbConnString": "mongodb://localhost:27017"
|
||||
},
|
||||
"RedisScripts": {
|
||||
"Scripts": {
|
||||
"Update": "RedisScript/RedisUpdateScript_v5.lua"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
"redisLongTimeCache": 60,
|
||||
"redisShortTimeCache": 30
|
||||
},
|
||||
"RedisScripts": {
|
||||
"Scripts": {
|
||||
"Update": "RedisScript/RedisUpdateScript_v6.lua"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"MP.Data": "Server=SQL2016DEV;Database=MoonPro; User ID=sa;Password=keyhammer16; integrated security=False; App=MP.IOC;",
|
||||
"MP.Flux": "Server=SQL2016DEV;Database=MoonPro_FluxData; User ID=sa;Password=keyhammer16; integrated security=False; MultipleActiveResultSets=True; App=MP.SPEC;",
|
||||
|
||||
Reference in New Issue
Block a user