Aggiunta migration + modifica record statistiche con MachineId (dest) in stats DAY
This commit is contained in:
@@ -15,11 +15,16 @@ namespace MP.Data.DbModels.Utils
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ambiente di destinazione IOC/IO (new/old)
|
||||
/// </summary>
|
||||
public string Destination { get; set; } = "";
|
||||
/// <summary>
|
||||
/// ID Macchina di riferimento
|
||||
/// </summary>
|
||||
public string MachineId { get; set; } = "";
|
||||
/// <summary>
|
||||
/// DataOra riferimento
|
||||
/// </summary>
|
||||
public DateTime Hour { get; set; }
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using MP.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MP.Data.Migrations.MoonPro_Utils
|
||||
{
|
||||
[DbContext(typeof(MoonPro_UtilsContext))]
|
||||
[Migration("20260422155939_UpdateAggrStat")]
|
||||
partial class UpdateAggrStat
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("SQL_Latin1_General_CP1_CI_AS")
|
||||
.HasAnnotation("ProductVersion", "6.0.36")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
|
||||
|
||||
modelBuilder.Entity("MP.Data.DbModels.Utils.StatsAggregatedModel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<double>("AvgDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<string>("Destination")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("Hour")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("MachineId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<double>("MaxDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<double>("MinDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<long>("NoReply")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<long>("RequestCount")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Destination", "MachineId", "Hour")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("idx_statsaggr_env_mach_hour")
|
||||
.HasFilter("[Destination] IS NOT NULL AND [MachineId] IS NOT NULL");
|
||||
|
||||
b.ToTable("stats_aggr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MP.Data.DbModels.Utils.StatsDetailModel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<double>("AvgDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<string>("Destination")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("Hour")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<double>("MaxDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<double>("MinDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<long>("NoReply")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<long>("RequestCount")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Destination", "Type", "Hour")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("idx_statsdet_hour_env_type")
|
||||
.HasFilter("[Destination] IS NOT NULL AND [Type] IS NOT NULL");
|
||||
|
||||
b.ToTable("stats_detail");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MP.Data.Migrations.MoonPro_Utils
|
||||
{
|
||||
public partial class UpdateAggrStat : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "idx_statsaggr_env_hour",
|
||||
table: "stats_aggr");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "MachineId",
|
||||
table: "stats_aggr",
|
||||
type: "nvarchar(450)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "idx_statsaggr_env_mach_hour",
|
||||
table: "stats_aggr",
|
||||
columns: new[] { "Destination", "MachineId", "Hour" },
|
||||
unique: true,
|
||||
filter: "[Destination] IS NOT NULL AND [MachineId] IS NOT NULL");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "idx_statsaggr_env_mach_hour",
|
||||
table: "stats_aggr");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MachineId",
|
||||
table: "stats_aggr");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "idx_statsaggr_env_hour",
|
||||
table: "stats_aggr",
|
||||
columns: new[] { "Destination", "Hour" },
|
||||
unique: true,
|
||||
filter: "[Destination] IS NOT NULL");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,9 @@ namespace MP.Data.Migrations.MoonPro_Utils
|
||||
b.Property<DateTime>("Hour")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("MachineId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<double>("MaxDuration")
|
||||
.HasColumnType("float");
|
||||
|
||||
@@ -54,10 +57,10 @@ namespace MP.Data.Migrations.MoonPro_Utils
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Destination", "Hour")
|
||||
b.HasIndex("Destination", "MachineId", "Hour")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("idx_statsaggr_env_hour")
|
||||
.HasFilter("[Destination] IS NOT NULL");
|
||||
.HasDatabaseName("idx_statsaggr_env_mach_hour")
|
||||
.HasFilter("[Destination] IS NOT NULL AND [MachineId] IS NOT NULL");
|
||||
|
||||
b.ToTable("stats_aggr");
|
||||
});
|
||||
|
||||
@@ -83,43 +83,12 @@ namespace MP.Data
|
||||
.HasIndex(x => new { x.Destination, x.Type, x.Hour })
|
||||
.HasDatabaseName("idx_statsdet_hour_env_type")
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<StatsAggregatedModel>()
|
||||
.HasIndex(x => new { x.Destination, x.Hour })
|
||||
.HasDatabaseName("idx_statsaggr_env_hour")
|
||||
.HasIndex(x => new { x.Destination, x.MachineId, x.Hour })
|
||||
.HasDatabaseName("idx_statsaggr_env_mach_hour")
|
||||
.IsUnique();
|
||||
|
||||
// modelBuilder.Entity<AnagArticoliModel>(entity =>
|
||||
// {
|
||||
// entity.HasKey(e => e.CodArticolo);
|
||||
|
||||
// entity.ToView("AnagArticoli");
|
||||
|
||||
// entity.Property(e => e.CodArticolo)
|
||||
// .IsRequired()
|
||||
// .HasMaxLength(50);
|
||||
|
||||
// entity.Property(e => e.DescArticolo)
|
||||
// .IsRequired()
|
||||
// .HasMaxLength(250);
|
||||
|
||||
// entity.Property(e => e.Disegno)
|
||||
// .IsRequired()
|
||||
// .HasMaxLength(50);
|
||||
|
||||
// entity.Property(e => e.Tipo)
|
||||
// .IsRequired()
|
||||
// .HasMaxLength(50);
|
||||
|
||||
// entity.Property(e => e.Azienda)
|
||||
// .IsRequired()
|
||||
// .HasMaxLength(50);
|
||||
// });
|
||||
|
||||
// modelBuilder.Entity<ParetoFluxLogDTO>(entity =>
|
||||
// {
|
||||
// entity.HasKey(e => new { e.IdxMacchina, e.CodFlux });
|
||||
// });
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,13 +93,13 @@ namespace MP.Data.Repository.Utils
|
||||
// Creiamo un dizionario per ricerca rapida O(1) basato sulla chiave univoca (Dest + Hour)
|
||||
// Usiamo una Tupla come chiave del dizionario
|
||||
var lookup = existingRecords.ToDictionary(
|
||||
x => (x.Destination, x.Hour),
|
||||
x => (x.Destination, x.MachineId, x.Hour),
|
||||
x => x
|
||||
);
|
||||
|
||||
foreach (var incoming in listRecords)
|
||||
{
|
||||
var key = (incoming.Destination, incoming.Hour);
|
||||
var key = (incoming.Destination, incoming.MachineId, incoming.Hour);
|
||||
if (lookup.TryGetValue(key, out var existing))
|
||||
{
|
||||
// --- CASO: UPDATE ---
|
||||
@@ -134,57 +134,6 @@ namespace MP.Data.Repository.Utils
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <inheritdoc />
|
||||
public async Task<int> UpsertManyAsyncOrig(List<StatsAggregatedModel> listRecords, bool removeOld)
|
||||
{
|
||||
int answ = 0;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// in primis se richiesto calcolo range periodo e svuoto...
|
||||
if (removeOld)
|
||||
{
|
||||
var firstRec = listRecords.OrderBy(x => x.Hour).FirstOrDefault();
|
||||
var lastRec = listRecords.OrderByDescending(x => x.Hour).FirstOrDefault();
|
||||
|
||||
if (firstRec != null && lastRec != null)
|
||||
{
|
||||
DateTime startDate = firstRec.Hour;
|
||||
DateTime endDate = lastRec.Hour;
|
||||
|
||||
var items = await dbCtx.DbSetStatsAggr
|
||||
.Where(x => x.Hour >= startDate && x.Hour <= endDate)
|
||||
.ToListAsync();
|
||||
|
||||
dbCtx.DbSetStatsAggr.RemoveRange(items);
|
||||
await dbCtx.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
await dbCtx
|
||||
.DbSetStatsAggr
|
||||
.AddRangeAsync(listRecords);
|
||||
|
||||
// salvo!
|
||||
answ = await dbCtx.SaveChangesAsync();
|
||||
|
||||
// commit transazione
|
||||
await tx.CommitAsync();
|
||||
|
||||
// libero memoria del changeTracker
|
||||
dbCtx.ChangeTracker.Clear();
|
||||
return answ;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<div class="card-header py-1">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="px-0 fw-bold">@Title</div>
|
||||
<div class="px-0">
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-1">
|
||||
<ul class="list-group">
|
||||
<ul class="list-group small">
|
||||
@foreach (var itemDet in ListPaged)
|
||||
{
|
||||
<li class="list-group-item @CheckSelect(itemDet.Label) d-flex justify-content-between align-items-start small py-1">
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<div class="card-header">
|
||||
<h3>Current Call Stats (24h)</h3>
|
||||
</div>
|
||||
<div class="card-body p-1">
|
||||
<div class="card-body px-1 py-0">
|
||||
<div class="row mb-2">
|
||||
<div class="col-3">
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<div class="card-header py-1">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="px-0 fw-bold">Avail Data</div>
|
||||
<div class="px-0">
|
||||
@@ -89,7 +89,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<MultiLine Id="@currTsId" AspRatio="2.5" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColorsMLine" backColor="@bgColorsMLine" lTens="0" Titles="@lineTitles" Stepped="false" yScale="logarithmic"></MultiLine>
|
||||
<MultiLine Id="@currTsId" AspRatio="3" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColorsMLine" backColor="@bgColorsMLine" lTens="0" Titles="@lineTitles" Stepped="false" yScale="logarithmic"></MultiLine>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>6.16.2604.2111</Version>
|
||||
<Version>6.16.2604.2218</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MP-IOC </i>
|
||||
<h4>Versione: 6.16.2604.2111</h4>
|
||||
<h4>Versione: 6.16.2604.2218</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.16.2604.2111
|
||||
6.16.2604.2218
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>6.16.2604.2111</version>
|
||||
<version>6.16.2604.2218</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>
|
||||
|
||||
@@ -43,75 +43,6 @@ namespace MP.IOC.Services
|
||||
/// </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_v6 = @"
|
||||
local key = KEYS[1]
|
||||
local countInc = tonumber(ARGV[1])
|
||||
local totalMsInc = tonumber(ARGV[2])
|
||||
local newMax = tonumber(ARGV[3])
|
||||
local newMin = tonumber(ARGV[4])
|
||||
local sentinel = tonumber(ARGV[5])
|
||||
|
||||
-- 1. Incremento Count e TotalDuration
|
||||
redis.call('HINCRBY', key, 'count', countInc)
|
||||
redis.call('HINCRBYFLOAT', key, 'totalMs', totalMsInc)
|
||||
|
||||
-- 2. Aggiornamento Max (solo se il nuovo valore è maggiore del precedente E non � la SentinelValue)
|
||||
local currentMax = redis.call('HGET', key, 'maxMs')
|
||||
if newMax < sentinel and (not currentMax or newMax > tonumber(currentMax)) then
|
||||
redis.call('HSET', key, 'maxMs', tostring(newMax))
|
||||
end
|
||||
|
||||
-- 3. Aggiornamento Min (solo se il nuovo valore è minore del precedente E non � la SentinelValue)
|
||||
local currentMin = redis.call('HGET', key, 'minMs')
|
||||
if newMin < sentinel and (not currentMin or newMin < tonumber(currentMin)) then
|
||||
redis.call('HSET', key, 'minMs', tostring(newMin))
|
||||
end
|
||||
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
|
||||
@@ -150,14 +81,21 @@ namespace MP.IOC.Services
|
||||
{
|
||||
string dest = "IO";
|
||||
string method = "NA";
|
||||
string machineId = "ALL";
|
||||
string rawKey = kv.Key;
|
||||
if (rawKey.Contains("|"))
|
||||
{
|
||||
var splitVal = rawKey.Split("|");
|
||||
dest = splitVal[0];
|
||||
method = splitVal[1];
|
||||
if (splitVal.Length > 1)
|
||||
method = splitVal[1];
|
||||
if (splitVal.Length > 2)
|
||||
machineId = splitVal[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
method = rawKey;
|
||||
}
|
||||
else { method = rawKey; }
|
||||
|
||||
var stat = kv.Value;
|
||||
var count = Interlocked.Read(ref stat.Count);
|
||||
@@ -168,7 +106,7 @@ namespace MP.IOC.Services
|
||||
? double.Parse(SentinelValue)
|
||||
: stat.MinDuration.TotalMilliseconds;
|
||||
|
||||
// --- LOGICA HOURLY (Per ogni route/method � una chiave distinta) ---
|
||||
// --- LOGICA HOURLY (Per ogni route/method e' una chiave distinta) ---
|
||||
var hourKey = HourBucketKey(dest, method, hourStart);
|
||||
var hoursIndex = HoursIndexKey(dest, method);
|
||||
var hourScore = ToEpochSeconds(hourStart);
|
||||
@@ -187,8 +125,8 @@ namespace MP.IOC.Services
|
||||
tasks.Add(batch.SortedSetAddAsync(hoursIndex, hourKey, hourScore));
|
||||
|
||||
// --- LOGICA DAILY (Aggregazione locale per evitare sovrascritture nel loop) ---
|
||||
var dayKey = DayBucketKey(dest, dayStart);
|
||||
var daysIndex = DaysIndexKey(dest);
|
||||
var dayKey = DayBucketKey(dest, machineId, dayStart);
|
||||
var daysIndex = DaysIndexKey(dest, machineId);
|
||||
var dayScore = ToEpochSeconds(dayStart);
|
||||
|
||||
if (!dailyAggregates.TryGetValue(dayKey, out var agg))
|
||||
@@ -255,18 +193,14 @@ namespace MP.IOC.Services
|
||||
|
||||
#region Private Methods
|
||||
|
||||
//private static string DayBucketKey(string dest, string method, DateTime dtRif)
|
||||
private static string DayBucketKey(string dest, DateTime dtRif)
|
||||
private static string DayBucketKey(string dest, string machId, DateTime dtRif)
|
||||
{
|
||||
return $"{_redisBaseKey}:stats:day:{dest}:{dtRif.ToString("yyyyMMdd", CultureInfo.InvariantCulture)}";
|
||||
//return $"{_redisBaseKey}:stats:day:{dest}:{method}:{dtRif.ToString("yyyyMMdd", CultureInfo.InvariantCulture)}";
|
||||
return $"{_redisBaseKey}:stats:day:{dest}:{machId}:{dtRif.ToString("yyyyMMdd", CultureInfo.InvariantCulture)}";
|
||||
}
|
||||
|
||||
//private static string DaysIndexKey(string dest, string method)
|
||||
private static string DaysIndexKey(string dest)
|
||||
private static string DaysIndexKey(string dest, string machId)
|
||||
{
|
||||
return $"{_redisBaseKey}:stats:days:{dest}";
|
||||
//return $"{_redisBaseKey}:stats:days:{dest}:{method}";
|
||||
return $"{_redisBaseKey}:stats:days:{dest}:{machId}";
|
||||
}
|
||||
|
||||
private static string HourBucketKey(string dest, string method, DateTime dtRif)
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace MP.IOC.Services
|
||||
foreach (var statKey in memberKeys)
|
||||
{
|
||||
var sKey = (RedisKey)$"{statKey}";
|
||||
if (!TryParseKeyMetadata(sKey, out string dest, out string method, out DateTime timestamp, out bool isHourType))
|
||||
if (!TryParseKeyMetadata(sKey, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType))
|
||||
continue;
|
||||
|
||||
// Verifica se la chiave fosse scaduta rispetto all'orario corrente
|
||||
@@ -150,6 +150,7 @@ namespace MP.IOC.Services
|
||||
aggrRecordsToInsert.Add(new StatsAggregatedModel
|
||||
{
|
||||
Destination = dest,
|
||||
MachineId = machId,
|
||||
Hour = timestamp,
|
||||
RequestCount = count,
|
||||
AvgDuration = totalMs / count,
|
||||
@@ -231,7 +232,7 @@ namespace MP.IOC.Services
|
||||
foreach (var statKey in memberKeys)
|
||||
{
|
||||
var sKey = (RedisKey)$"{statKey}";
|
||||
if (!TryParseKeyMetadata(sKey, out string dest, out string method, out DateTime timestamp, out bool isHourType))
|
||||
if (!TryParseKeyMetadata(sKey, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType))
|
||||
continue;
|
||||
|
||||
// Verifica se la chiave fosse scaduta rispetto all'orario corrente
|
||||
@@ -309,9 +310,13 @@ namespace MP.IOC.Services
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryParseKeyMetadata(RedisKey key, out string dest, out string method, out DateTime timestamp, out bool isHourType)
|
||||
private bool TryParseKeyMetadata(RedisKey key, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType)
|
||||
{
|
||||
dest = "NA"; method = "NA"; timestamp = DateTime.MinValue; isHourType = true;
|
||||
dest = "NA";
|
||||
method = "NA";
|
||||
machId = "ALL";
|
||||
timestamp = DateTime.MinValue;
|
||||
isHourType = true;
|
||||
try
|
||||
{
|
||||
string k = key.ToString();
|
||||
@@ -337,7 +342,17 @@ namespace MP.IOC.Services
|
||||
{
|
||||
isHourType = false;
|
||||
method = "DAILY";
|
||||
if (DateTime.TryParseExact(parts[3], "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt))
|
||||
string rawDate = "";
|
||||
if (parts.Length >= 5)
|
||||
{
|
||||
machId = parts[3];
|
||||
rawDate = parts[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
rawDate = parts[3];
|
||||
}
|
||||
if (DateTime.TryParseExact(rawDate, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt))
|
||||
{
|
||||
timestamp = dt;
|
||||
return true;
|
||||
|
||||
@@ -63,10 +63,24 @@ namespace MP.IOC.Services
|
||||
|
||||
Log.Debug($"PathBase={context.Request.PathBase} | Path={context.Request.Path} | relativePath={relativePath}");
|
||||
|
||||
// da calcolare metodo...
|
||||
// Procedo a calcolare metodo e ID...
|
||||
string metodo = "/";
|
||||
string id = "ALL";
|
||||
if (!string.IsNullOrEmpty(relativePath))
|
||||
{
|
||||
// Rimuovo eventuale query string
|
||||
var pathOnly = relativePath.Split('?')[0];
|
||||
|
||||
// Splitto per /
|
||||
var parts = pathOnly.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length > 0)
|
||||
metodo = parts[0];
|
||||
|
||||
if (parts.Length > 1)
|
||||
id = parts[1];
|
||||
|
||||
#if false
|
||||
// splitto se ho /...
|
||||
if (relativePath.Contains("/"))
|
||||
{
|
||||
@@ -75,9 +89,11 @@ namespace MP.IOC.Services
|
||||
else
|
||||
{
|
||||
metodo = relativePath;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Log.Debug($"Metodo: {metodo}");
|
||||
|
||||
Log.Debug($"Metodo: {metodo} | machineId: {id}");
|
||||
|
||||
var (oldW, newW) = _weightProvider.GetWeightsFor(metodo);
|
||||
var pickNew = DecideByWeights(oldW, newW);
|
||||
@@ -102,7 +118,7 @@ namespace MP.IOC.Services
|
||||
|
||||
try
|
||||
{
|
||||
string sKey = $"{target}|{metodo}";
|
||||
string sKey = $"{target}|{metodo}|{id}";
|
||||
|
||||
// Registra scelta
|
||||
_stats.Record(sKey);
|
||||
|
||||
Reference in New Issue
Block a user