From 1cdac18192b1c1ddd746ad3d5d6a5434d739ae1e Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Wed, 8 Apr 2026 08:26:05 +0200 Subject: [PATCH] Revisione modello dati + migration, bloccato invio dati al DB per revisione preliminare metodi --- .../DbModels/Utils/StatsAggregatedModel.cs | 4 +- MP.Data/DbModels/Utils/StatsDetailModel.cs | 4 +- ...r.cs => 20260408062523_InitDb.Designer.cs} | 14 ++-- ...203_InitDb.cs => 20260408062523_InitDb.cs} | 12 +-- .../MoonPro_UtilsContextModelSnapshot.cs | 12 +-- MP.Data/MoonPro_UtilsContext.cs | 4 +- .../Repository/Utils/StatsAggrRepository.cs | 10 +-- .../Repository/Utils/StatsDetailRepository.cs | 16 ++-- MP.IOC/Controllers/IOBController.cs | 76 +++++++++---------- MP.IOC/Program.cs | 6 +- MP.IOC/Resources/ChangeLog.html | 2 +- MP.IOC/Resources/VersNum.txt | 2 +- MP.IOC/Resources/manifest.xml | 2 +- ...sFlushService.cs => MetricsCalcService.cs} | 71 ++++++++++------- MP.IOC/Services/MetricsDbFlushService.cs | 47 +++++++----- MP.IOC/Services/RouteManager.cs | 10 ++- MP.IOC/Services/RouteStatsManager.cs | 37 ++++++--- MP.IOC/appsettings.json | 4 +- 18 files changed, 191 insertions(+), 142 deletions(-) rename MP.Data/Migrations/MoonPro_Utils/{20260408050203_InitDb.Designer.cs => 20260408062523_InitDb.Designer.cs} (89%) rename MP.Data/Migrations/MoonPro_Utils/{20260408050203_InitDb.cs => 20260408062523_InitDb.cs} (86%) rename MP.IOC/Services/{MetricsFlushService.cs => MetricsCalcService.cs} (60%) diff --git a/MP.Data/DbModels/Utils/StatsAggregatedModel.cs b/MP.Data/DbModels/Utils/StatsAggregatedModel.cs index d7a3e721..ece10c4b 100644 --- a/MP.Data/DbModels/Utils/StatsAggregatedModel.cs +++ b/MP.Data/DbModels/Utils/StatsAggregatedModel.cs @@ -16,9 +16,9 @@ namespace MP.Data.DbModels.Utils [Key] public int Id { get; set; } /// - /// Ambiente IOC/IO (new/old) + /// Ambiente di destinazione IOC/IO (new/old) /// - public string Envir { get; set; } = ""; + public string Destination { get; set; } = ""; /// /// DataOra riferimento /// diff --git a/MP.Data/DbModels/Utils/StatsDetailModel.cs b/MP.Data/DbModels/Utils/StatsDetailModel.cs index 351b45f4..afc4d62c 100644 --- a/MP.Data/DbModels/Utils/StatsDetailModel.cs +++ b/MP.Data/DbModels/Utils/StatsDetailModel.cs @@ -16,9 +16,9 @@ namespace MP.Data.DbModels.Utils [Key] public int Id { get; set; } /// - /// Ambiente IOC/IO (new/old) + /// Ambiente di destinazione IOC/IO (new/old) /// - public string Envir { get; set; } = ""; + public string Destination { get; set; } = ""; /// /// Codice tipo (metodo chiamato) /// diff --git a/MP.Data/Migrations/MoonPro_Utils/20260408050203_InitDb.Designer.cs b/MP.Data/Migrations/MoonPro_Utils/20260408062523_InitDb.Designer.cs similarity index 89% rename from MP.Data/Migrations/MoonPro_Utils/20260408050203_InitDb.Designer.cs rename to MP.Data/Migrations/MoonPro_Utils/20260408062523_InitDb.Designer.cs index b2f09de2..f8f570ad 100644 --- a/MP.Data/Migrations/MoonPro_Utils/20260408050203_InitDb.Designer.cs +++ b/MP.Data/Migrations/MoonPro_Utils/20260408062523_InitDb.Designer.cs @@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace MP.Data.Migrations.MoonPro_Utils { [DbContext(typeof(MoonPro_UtilsContext))] - [Migration("20260408050203_InitDb")] + [Migration("20260408062523_InitDb")] partial class InitDb { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -36,7 +36,7 @@ namespace MP.Data.Migrations.MoonPro_Utils b.Property("AvgDuration") .HasColumnType("float"); - b.Property("Envir") + b.Property("Destination") .HasColumnType("nvarchar(450)"); b.Property("Hour") @@ -56,10 +56,10 @@ namespace MP.Data.Migrations.MoonPro_Utils b.HasKey("Id"); - b.HasIndex("Envir", "Hour") + b.HasIndex("Destination", "Hour") .IsUnique() .HasDatabaseName("idx_statsaggr_env_hour") - .HasFilter("[Envir] IS NOT NULL"); + .HasFilter("[Destination] IS NOT NULL"); b.ToTable("stats_aggr"); }); @@ -75,7 +75,7 @@ namespace MP.Data.Migrations.MoonPro_Utils b.Property("AvgDuration") .HasColumnType("float"); - b.Property("Envir") + b.Property("Destination") .HasColumnType("nvarchar(450)"); b.Property("Hour") @@ -98,10 +98,10 @@ namespace MP.Data.Migrations.MoonPro_Utils b.HasKey("Id"); - b.HasIndex("Envir", "Type", "Hour") + b.HasIndex("Destination", "Type", "Hour") .IsUnique() .HasDatabaseName("idx_statsdet_hour_env_type") - .HasFilter("[Envir] IS NOT NULL AND [Type] IS NOT NULL"); + .HasFilter("[Destination] IS NOT NULL AND [Type] IS NOT NULL"); b.ToTable("stats_detail"); }); diff --git a/MP.Data/Migrations/MoonPro_Utils/20260408050203_InitDb.cs b/MP.Data/Migrations/MoonPro_Utils/20260408062523_InitDb.cs similarity index 86% rename from MP.Data/Migrations/MoonPro_Utils/20260408050203_InitDb.cs rename to MP.Data/Migrations/MoonPro_Utils/20260408062523_InitDb.cs index 2f40f4fa..360706c2 100644 --- a/MP.Data/Migrations/MoonPro_Utils/20260408050203_InitDb.cs +++ b/MP.Data/Migrations/MoonPro_Utils/20260408062523_InitDb.cs @@ -15,7 +15,7 @@ namespace MP.Data.Migrations.MoonPro_Utils { Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - Envir = table.Column(type: "nvarchar(450)", nullable: true), + Destination = table.Column(type: "nvarchar(450)", nullable: true), Hour = table.Column(type: "datetime2", nullable: false), RequestCount = table.Column(type: "bigint", nullable: false), AvgDuration = table.Column(type: "float", nullable: false), @@ -34,7 +34,7 @@ namespace MP.Data.Migrations.MoonPro_Utils { Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - Envir = table.Column(type: "nvarchar(450)", nullable: true), + Destination = table.Column(type: "nvarchar(450)", nullable: true), Type = table.Column(type: "nvarchar(450)", nullable: true), Hour = table.Column(type: "datetime2", nullable: false), RequestCount = table.Column(type: "bigint", nullable: false), @@ -51,16 +51,16 @@ namespace MP.Data.Migrations.MoonPro_Utils migrationBuilder.CreateIndex( name: "idx_statsaggr_env_hour", table: "stats_aggr", - columns: new[] { "Envir", "Hour" }, + columns: new[] { "Destination", "Hour" }, unique: true, - filter: "[Envir] IS NOT NULL"); + filter: "[Destination] IS NOT NULL"); migrationBuilder.CreateIndex( name: "idx_statsdet_hour_env_type", table: "stats_detail", - columns: new[] { "Envir", "Type", "Hour" }, + columns: new[] { "Destination", "Type", "Hour" }, unique: true, - filter: "[Envir] IS NOT NULL AND [Type] IS NOT NULL"); + filter: "[Destination] IS NOT NULL AND [Type] IS NOT NULL"); } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/MP.Data/Migrations/MoonPro_Utils/MoonPro_UtilsContextModelSnapshot.cs b/MP.Data/Migrations/MoonPro_Utils/MoonPro_UtilsContextModelSnapshot.cs index 6b2eed7c..ab41958b 100644 --- a/MP.Data/Migrations/MoonPro_Utils/MoonPro_UtilsContextModelSnapshot.cs +++ b/MP.Data/Migrations/MoonPro_Utils/MoonPro_UtilsContextModelSnapshot.cs @@ -34,7 +34,7 @@ namespace MP.Data.Migrations.MoonPro_Utils b.Property("AvgDuration") .HasColumnType("float"); - b.Property("Envir") + b.Property("Destination") .HasColumnType("nvarchar(450)"); b.Property("Hour") @@ -54,10 +54,10 @@ namespace MP.Data.Migrations.MoonPro_Utils b.HasKey("Id"); - b.HasIndex("Envir", "Hour") + b.HasIndex("Destination", "Hour") .IsUnique() .HasDatabaseName("idx_statsaggr_env_hour") - .HasFilter("[Envir] IS NOT NULL"); + .HasFilter("[Destination] IS NOT NULL"); b.ToTable("stats_aggr"); }); @@ -73,7 +73,7 @@ namespace MP.Data.Migrations.MoonPro_Utils b.Property("AvgDuration") .HasColumnType("float"); - b.Property("Envir") + b.Property("Destination") .HasColumnType("nvarchar(450)"); b.Property("Hour") @@ -96,10 +96,10 @@ namespace MP.Data.Migrations.MoonPro_Utils b.HasKey("Id"); - b.HasIndex("Envir", "Type", "Hour") + b.HasIndex("Destination", "Type", "Hour") .IsUnique() .HasDatabaseName("idx_statsdet_hour_env_type") - .HasFilter("[Envir] IS NOT NULL AND [Type] IS NOT NULL"); + .HasFilter("[Destination] IS NOT NULL AND [Type] IS NOT NULL"); b.ToTable("stats_detail"); }); diff --git a/MP.Data/MoonPro_UtilsContext.cs b/MP.Data/MoonPro_UtilsContext.cs index cf8eb260..9b4eb6eb 100644 --- a/MP.Data/MoonPro_UtilsContext.cs +++ b/MP.Data/MoonPro_UtilsContext.cs @@ -80,11 +80,11 @@ namespace MP.Data // indici tabelle stats modelBuilder.Entity() - .HasIndex(x => new { x.Envir, x.Type, x.Hour }) + .HasIndex(x => new { x.Destination, x.Type, x.Hour }) .HasDatabaseName("idx_statsdet_hour_env_type") .IsUnique(); modelBuilder.Entity() - .HasIndex(x => new { x.Envir, x.Hour }) + .HasIndex(x => new { x.Destination, x.Hour }) .HasDatabaseName("idx_statsaggr_env_hour") .IsUnique(); diff --git a/MP.Data/Repository/Utils/StatsAggrRepository.cs b/MP.Data/Repository/Utils/StatsAggrRepository.cs index 90077131..29131ba6 100644 --- a/MP.Data/Repository/Utils/StatsAggrRepository.cs +++ b/MP.Data/Repository/Utils/StatsAggrRepository.cs @@ -85,22 +85,22 @@ namespace MP.Data.Repository.Utils var existingRecords = await dbCtx .DbSetStatsAggr .Where(x => listRecords.Select(r => r.Hour).Contains(x.Hour) && - listRecords.Select(r => r.Envir).Contains(x.Envir)) + listRecords.Select(r => r.Destination).Contains(x.Destination)) .ToListAsync(); if (existingRecords.Count > 0) { - var existingHours = existingRecords.Select(r => new { r.Hour, r.Envir }).ToHashSet(); + var existingHours = existingRecords.Select(r => new { r.Hour, r.Destination }).ToHashSet(); var recordsToUpdate = listRecords.Where(r => - existingHours.Contains(new { Hour = r.Hour, Envir = r.Envir })).ToList(); + existingHours.Contains(new { Hour = r.Hour, Destination = r.Destination })).ToList(); var recordsToAdd = listRecords.Where(r => - !existingHours.Contains(new { Hour = r.Hour, Envir = r.Envir })).ToList(); + !existingHours.Contains(new { Hour = r.Hour, Destination = r.Destination })).ToList(); foreach (var updateRec in recordsToUpdate) { - var existing = existingRecords.First(x => x.Hour == updateRec.Hour && x.Envir == updateRec.Envir); + var existing = existingRecords.First(x => x.Hour == updateRec.Hour && x.Destination == updateRec.Destination); existing.RequestCount = updateRec.RequestCount; existing.AvgDuration = updateRec.AvgDuration; existing.MaxDuration = updateRec.MaxDuration; diff --git a/MP.Data/Repository/Utils/StatsDetailRepository.cs b/MP.Data/Repository/Utils/StatsDetailRepository.cs index 2f0d4036..038e9213 100644 --- a/MP.Data/Repository/Utils/StatsDetailRepository.cs +++ b/MP.Data/Repository/Utils/StatsDetailRepository.cs @@ -31,7 +31,7 @@ namespace MP.Data.Repository.Utils .Where(x => x.Hour >= dtStart && x.Hour <= dtEnd); if (!string.IsNullOrEmpty(sEnvir)) - query = query.Where(x => x.Envir == sEnvir); + query = query.Where(x => x.Destination == sEnvir); if (!string.IsNullOrEmpty(sType)) query = query.Where(x => x.Type == sType); @@ -39,7 +39,7 @@ namespace MP.Data.Repository.Utils answ = await query .AsNoTracking() .OrderBy(x => x.Hour) - .ThenBy(x => x.Envir) + .ThenBy(x => x.Destination) .ThenBy(x => x.Type) .ToListAsync(); @@ -55,7 +55,7 @@ namespace MP.Data.Repository.Utils var query = dbCtx.DbSetStatsDet.AsQueryable(); if (!string.IsNullOrEmpty(sEnvir)) - query = query.Where(x => x.Envir == sEnvir); + query = query.Where(x => x.Destination == sEnvir); if (!string.IsNullOrEmpty(sType)) query = query.Where(x => x.Type == sType); @@ -105,22 +105,22 @@ namespace MP.Data.Repository.Utils // ora preparo inserimento massivo var existingRecords = await dbCtx .DbSetStatsDet - .Where(x => listRecords.Select(r => new { r.Hour, r.Envir, r.Type }).Contains(new { Hour = x.Hour, Envir = x.Envir, Type = x.Type })) + .Where(x => listRecords.Select(r => new { r.Hour, r.Destination, r.Type }).Contains(new { Hour = x.Hour, Destination = x.Destination, Type = x.Type })) .ToListAsync(); if (existingRecords.Count > 0) { - var existingKeys = existingRecords.Select(r => new { r.Hour, r.Envir, r.Type }).ToHashSet(); + var existingKeys = existingRecords.Select(r => new { r.Hour, r.Destination, r.Type }).ToHashSet(); var recordsToUpdate = listRecords.Where(r => - existingKeys.Contains(new { Hour = r.Hour, Envir = r.Envir, Type = r.Type })).ToList(); + existingKeys.Contains(new { Hour = r.Hour, Destination = r.Destination, Type = r.Type })).ToList(); var recordsToAdd = listRecords.Where(r => - !existingKeys.Contains(new { Hour = r.Hour, Envir = r.Envir, Type = r.Type })).ToList(); + !existingKeys.Contains(new { Hour = r.Hour, Destination = r.Destination, Type = r.Type })).ToList(); foreach (var updateRec in recordsToUpdate) { - var existing = Enumerable.First(existingRecords, (Func)(x => x.Hour == updateRec.Hour && x.Envir == updateRec.Envir && x.Type == updateRec.Type)); + var existing = Enumerable.First((IEnumerable)existingRecords, (Func)(x => x.Hour == updateRec.Hour && x.Destination == updateRec.Destination && x.Type == updateRec.Type)); existing.RequestCount = updateRec.RequestCount; existing.AvgDuration = updateRec.AvgDuration; existing.MaxDuration = updateRec.MaxDuration; diff --git a/MP.IOC/Controllers/IOBController.cs b/MP.IOC/Controllers/IOBController.cs index 44a2eca7..12f2241a 100644 --- a/MP.IOC/Controllers/IOBController.cs +++ b/MP.IOC/Controllers/IOBController.cs @@ -223,7 +223,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in enabled{0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in enabled{0}{1}", Destination.NewLine, exc)); // answ = "NO"; // } // } @@ -264,7 +264,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase deserializzazione inputJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase deserializzazione inputJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // // se ho qualcosa da processare... @@ -292,7 +292,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase invio valori inputJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase invio valori inputJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -375,7 +375,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Eccezione in recupero fixDailyDossier{Envir.NewLine}{exc}", tipoLog.EXCEPTION); + // logger.lg.scriviLog($"Eccezione in recupero fixDailyDossier{Destination.NewLine}{exc}", tipoLog.EXCEPTION); // } // return answ; //} @@ -415,7 +415,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Eccezione in recupero fixDailyOdl{Envir.NewLine}{exc}", tipoLog.EXCEPTION); + // logger.lg.scriviLog($"Eccezione in recupero fixDailyOdl{Destination.NewLine}{exc}", tipoLog.EXCEPTION); // } // return answ; //} @@ -444,7 +444,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in flog{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in flog{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -484,7 +484,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase deserializzazione flogJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase deserializzazione flogJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // // se ho qualcosa da processare... @@ -506,7 +506,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase invio valori flogJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase invio valori flogJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // // leggo parametri correnti... @@ -555,7 +555,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase salvataggio innovazioni parametri correnti da flogJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase salvataggio innovazioni parametri correnti da flogJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -687,7 +687,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in counter (get){0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in counter (get){0}{1}", Destination.NewLine, exc)); // answ = "NO"; // } // return answ; @@ -710,7 +710,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in counter TC (get){0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in counter TC (get){0}{1}", Destination.NewLine, exc)); // answ = "NO"; // } // return answ; @@ -764,7 +764,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in currODL (get){0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in currODL (get){0}{1}", Destination.NewLine, exc)); // answ = "NO"; // } // return answ; @@ -792,7 +792,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Eccezione in recupero getCurrOdlRow{Envir.NewLine}{exc}", tipoLog.EXCEPTION); + // logger.lg.scriviLog($"Eccezione in recupero getCurrOdlRow{Destination.NewLine}{exc}", tipoLog.EXCEPTION); // } // return answ; //} @@ -822,7 +822,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Eccezione in recupero getCurrOdlStart{Envir.NewLine}{exc}", tipoLog.EXCEPTION); + // logger.lg.scriviLog($"Eccezione in recupero getCurrOdlStart{Destination.NewLine}{exc}", tipoLog.EXCEPTION); // } // return answ.ToString("yyyy-MM-dd HH:mm:ss"); //} @@ -879,7 +879,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Eccezione in recupero getCurrStatoRow{Envir.NewLine}{exc}", tipoLog.EXCEPTION); + // logger.lg.scriviLog($"Eccezione in recupero getCurrStatoRow{Destination.NewLine}{exc}", tipoLog.EXCEPTION); // } // return answ; //} @@ -909,7 +909,7 @@ namespace MP.IOC.Controllers // currFile = new MapoSDK.smallFile() // { // fileName = item.Nome, - // content = fileContent.Replace("\r\n", Envir.NewLine) + // content = fileContent.Replace("\r\n", Destination.NewLine) // }; // objFiles.fileList.Add(currFile); // } @@ -918,7 +918,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in uploadFile{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in uploadFile{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -958,7 +958,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Eccezione in recupero getIdlePeriod{Envir.NewLine}{exc}", tipoLog.EXCEPTION); + // logger.lg.scriviLog($"Eccezione in recupero getIdlePeriod{Destination.NewLine}{exc}", tipoLog.EXCEPTION); // } // return answ; //} @@ -1189,7 +1189,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in getObjItems{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in getObjItems{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -1227,7 +1227,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in getCurrParams{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in getCurrParams{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -1391,7 +1391,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in processInput{0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in processInput{0}{1}", Destination.NewLine, exc)); // answ = "NO"; // } // return answ; @@ -1432,7 +1432,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in liveJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in liveJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -1445,7 +1445,7 @@ namespace MP.IOC.Controllers // DateTime dataOraEvento = DateTime.Now; // if (memLayer.ML.CRI("_logLevel") > 6) // { - // logger.lg.scriviLog($"Valori Live:{Envir.NewLine}idxMacchina: {id}{Envir.NewLine}liveData: {liveData}", tipoLog.INFO); + // logger.lg.scriviLog($"Valori Live:{Destination.NewLine}idxMacchina: {id}{Destination.NewLine}liveData: {liveData}", tipoLog.INFO); // } // try // { @@ -1454,7 +1454,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in liveRec{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in liveRec{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -1497,7 +1497,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase deserializzazione rawTransfJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase deserializzazione rawTransfJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // // se ho qualcosa da processare... @@ -1559,7 +1559,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase invio valori rawTransfJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase invio valori rawTransfJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -1726,7 +1726,7 @@ namespace MP.IOC.Controllers // // chiamo metodo update direttamente! // MtcDataModelArchive.man.saveMachineDataItems(id, dataItems); // answ = "OK"; - // logger.lg.scriviLog($"Effettuato salvataggio saveDataItems per id {id}:{Envir.NewLine}{content}"); + // logger.lg.scriviLog($"Effettuato salvataggio saveDataItems per id {id}:{Destination.NewLine}{content}"); // } // } // catch @@ -1757,7 +1757,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in savePzCountInc{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in savePzCountInc{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -1848,7 +1848,7 @@ namespace MP.IOC.Controllers // { // if (memLayer.ML.CRI("_logLevel") > 5) // { - // string errore = string.Format("Errore: {0}{1}", Envir.NewLine, exc); + // string errore = string.Format("Errore: {0}{1}", Destination.NewLine, exc); // logger.lg.scriviLog(errore, tipoLog.EXCEPTION); // } // } @@ -1893,7 +1893,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in counter (set){0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in counter (set){0}{1}", Destination.NewLine, exc)); // } // return answ; //} @@ -1990,7 +1990,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in setCurrParams{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in setCurrParams{Destination.NewLine}{exc}"); // answ = "EXC"; // } // } @@ -2016,7 +2016,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog(string.Format("Errore in sLog{0}{1}", Envir.NewLine, exc)); + // logger.lg.scriviLog(string.Format("Errore in sLog{0}{1}", Destination.NewLine, exc)); // answ = "NO"; // } // } @@ -2065,7 +2065,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in ulog{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in ulog{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -2106,7 +2106,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase deserializzazione ulogJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase deserializzazione ulogJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // // se ho qualcosa da processare... @@ -2128,7 +2128,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in fase invio valori ulogJson{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in fase invio valori ulogJson{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -2174,7 +2174,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in uploadFile{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in uploadFile{Destination.NewLine}{exc}"); // answ = "NO"; // } // return answ; @@ -2223,7 +2223,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in upsertObjItems{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in upsertObjItems{Destination.NewLine}{exc}"); // answ = "NO"; // } // } @@ -2267,7 +2267,7 @@ namespace MP.IOC.Controllers // } // catch (Exception exc) // { - // logger.lg.scriviLog($"Errore in {caller}{Envir.NewLine}{exc}"); + // logger.lg.scriviLog($"Errore in {caller}{Destination.NewLine}{exc}"); // answ = "NO"; // } diff --git a/MP.IOC/Program.cs b/MP.IOC/Program.cs index fd182e0b..9d068f62 100644 --- a/MP.IOC/Program.cs +++ b/MP.IOC/Program.cs @@ -61,11 +61,7 @@ logger.Info("YARP reverse proxy configured"); // base services builder.Services.AddSingleton(); builder.Services.AddSingleton(); -builder.Services.AddHostedService(); - -// da rivedere -#if true -#endif +builder.Services.AddHostedService(); builder.Services.AddHostedService(); // MP.Data DbContext for Stats repositories diff --git a/MP.IOC/Resources/ChangeLog.html b/MP.IOC/Resources/ChangeLog.html index f23403c1..36669b87 100644 --- a/MP.IOC/Resources/ChangeLog.html +++ b/MP.IOC/Resources/ChangeLog.html @@ -1,6 +1,6 @@ Modulo MP-IOC -

Versione: 6.16.2604.807

+

Versione: 6.16.2604.808


Note di rilascio:
  • diff --git a/MP.IOC/Resources/VersNum.txt b/MP.IOC/Resources/VersNum.txt index 30d146d4..dd1e9d83 100644 --- a/MP.IOC/Resources/VersNum.txt +++ b/MP.IOC/Resources/VersNum.txt @@ -1 +1 @@ -6.16.2604.807 +6.16.2604.808 diff --git a/MP.IOC/Resources/manifest.xml b/MP.IOC/Resources/manifest.xml index 6dae4f08..5503552d 100644 --- a/MP.IOC/Resources/manifest.xml +++ b/MP.IOC/Resources/manifest.xml @@ -1,6 +1,6 @@ - 6.16.2604.807 + 6.16.2604.808 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/MetricsFlushService.cs b/MP.IOC/Services/MetricsCalcService.cs similarity index 60% rename from MP.IOC/Services/MetricsFlushService.cs rename to MP.IOC/Services/MetricsCalcService.cs index b0196fad..226ac493 100644 --- a/MP.IOC/Services/MetricsFlushService.cs +++ b/MP.IOC/Services/MetricsCalcService.cs @@ -4,12 +4,17 @@ using System.Globalization; namespace MP.IOC.Services { - public class MetricsFlushService : BackgroundService + public class MetricsCalcService : BackgroundService { #region Public Constructors - //public MetricsFlushService(RouteStatsManager stats, ILogger logger, IConfiguration config) - public MetricsFlushService(RouteStatsManager stats, IConfiguration config, IConnectionMultiplexer mux) + /// + /// Metodo x calcolo metriche/statistiche di esecuzone realtime + /// + /// + /// + /// + public MetricsCalcService(RouteStatsManager stats, IConfiguration config, IConnectionMultiplexer mux) { _stats = stats; _config = config; @@ -23,7 +28,7 @@ namespace MP.IOC.Services protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - var interval = _config.GetValue("RouteMan:FlushIntervalSeconds", 30); + var interval = _config.GetValue("RouteMan:MetricCalcIntervalSeconds", 20); while (!stoppingToken.IsCancellationRequested) { try @@ -33,29 +38,44 @@ namespace MP.IOC.Services if (snapshot.Count == 0) continue; - var utcNow = DateTime.Now; - var hourStart = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, utcNow.Hour, 0, 0); - var dayStart = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, 0, 0, 0); + var adesso = DateTime.Now; + var hourStart = new DateTime(adesso.Year, adesso.Month, adesso.Day, adesso.Hour, 0, 0); + var dayStart = new DateTime(adesso.Year, adesso.Month, adesso.Day, 0, 0, 0); foreach (var kv in snapshot) { - var method = kv.Key; + string dest = "IO"; + string method = "NA"; + // verifico se ho chiave completo (dest+method) o parziale + string rawKey = kv.Key; + if (rawKey.Contains("|")) + { + var splitVal = rawKey.Split("|"); + dest = splitVal[0]; + method = splitVal[1]; + } + else + { + method = rawKey; + } +#if false + var method = kv.Key; +#endif var stat = kv.Value; var count = Interlocked.Read(ref stat.Count); var totalMs = stat.TotalDuration.TotalMilliseconds; var maxMs = stat.MaxDuration.TotalMilliseconds; var minMs = (stat.MinDuration == TimeSpan.MaxValue) ? 0 : stat.MinDuration.TotalMilliseconds; - Log.Info("Method {method} Count {count} TotalDurationMs {totalMs} MaxDurationMs {maxMs} MinDurationMs {minMs} Destinations {dests}", - method, count, totalMs, maxMs, minMs, string.Join(",", stat.Destinations.Select(x => $"{x.Key}:{x.Value}"))); + Log.Info($"Dest {dest} | Method {method} | Count {count} | TotalDurationMs {totalMs} | MaxDurationMs {maxMs} | MinDurationMs {minMs}"); if (_db == null) continue; // Keys - var hourKey = HourBucketKey(method, hourStart); - var hoursIndex = HoursIndexKey(method); - var dayKey = DayBucketKey(method, dayStart); - var daysIndex = DaysIndexKey(method); + var hourKey = HourBucketKey(dest, method, hourStart); + var hoursIndex = HoursIndexKey(dest, method); + var dayKey = DayBucketKey(dest, method, dayStart); + var daysIndex = DaysIndexKey(dest, method); // Use batch to reduce roundtrips var batch = _db.CreateBatch(); @@ -82,8 +102,8 @@ namespace MP.IOC.Services batch.Execute(); // Await tasks to ensure completion - await Task.WhenAll(taskHourCount, taskHourTotal, taskHourMax, taskHourMin, - taskDayCount, taskDayTotal, taskDayMax, taskDayMin, + await Task.WhenAll(taskHourCount, taskHourTotal, taskHourMax, taskHourMin, + taskDayCount, taskDayTotal, taskDayMax, taskDayMin, taskZAddHour, taskZAddDay); } @@ -101,9 +121,6 @@ namespace MP.IOC.Services #region Private Fields - private const int MaxDailyBuckets = 365; - private const int MaxHourlyBuckets = 24 * 10; - private static string _redisBaseKey = ""; private static Logger Log = LogManager.GetCurrentClassLogger(); private readonly IConfiguration _config; @@ -114,24 +131,24 @@ namespace MP.IOC.Services #region Private Methods - private static string DayBucketKey(string method, DateTime dtRif) + private static string DayBucketKey(string dest, string method, DateTime dtRif) { - return $"{_redisBaseKey}:stats:day:{method}:{dtRif.ToString("yyyyMMdd", CultureInfo.InvariantCulture)}"; + return $"{_redisBaseKey}:stats:day:{dest}:{method}:{dtRif.ToString("yyyyMMdd", CultureInfo.InvariantCulture)}"; } - private static string DaysIndexKey(string method) + private static string DaysIndexKey(string dest, string method) { - return $"{_redisBaseKey}:stats:days:{method}"; + return $"{_redisBaseKey}:stats:days:{dest}:{method}"; } - private static string HourBucketKey(string method, DateTime dtRif) + private static string HourBucketKey(string dest, string method, DateTime dtRif) { - return $"{_redisBaseKey}:stats:hour:{method}:{dtRif.ToString("yyyyMMddHH", CultureInfo.InvariantCulture)}"; + return $"{_redisBaseKey}:stats:hour:{dest}:{method}:{dtRif.ToString("yyyyMMddHH", CultureInfo.InvariantCulture)}"; } - private static string HoursIndexKey(string method) + private static string HoursIndexKey(string dest, string method) { - return $"{_redisBaseKey}:stats:hours:{method}"; + return $"{_redisBaseKey}:stats:hours:{dest}:{method}"; } private static long ToEpochSeconds(DateTime dt) diff --git a/MP.IOC/Services/MetricsDbFlushService.cs b/MP.IOC/Services/MetricsDbFlushService.cs index f55b34b9..c6ef4be5 100644 --- a/MP.IOC/Services/MetricsDbFlushService.cs +++ b/MP.IOC/Services/MetricsDbFlushService.cs @@ -9,10 +9,7 @@ namespace MP.IOC.Services public class MetricsDbFlushService : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; - private const int FlushIntervalSeconds = 30; private readonly RouteStatsManager _stats; - //private readonly IStatsAggrService _aggrService; - //private readonly IStatsDetailService _detailService; private readonly IConfiguration _config; private readonly IDatabase _db; private static readonly Logger Log = LogManager.GetCurrentClassLogger(); @@ -20,22 +17,18 @@ namespace MP.IOC.Services public MetricsDbFlushService( RouteStatsManager stats, IServiceScopeFactory scopeFactory, - //IStatsAggrService aggrService, - //IStatsDetailService detailService, IConfiguration config, IConnectionMultiplexer mux) { _stats = stats; _scopeFactory = scopeFactory; - //_aggrService = aggrService; - //_detailService = detailService; _config = config; _db = mux.GetDatabase(); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - var interval = _config.GetValue("RouteMan:FlushIntervalSeconds", FlushIntervalSeconds); + var interval = _config.GetValue("RouteMan:MetricFlushIntervalSeconds", 120); while (!stoppingToken.IsCancellationRequested) { @@ -119,7 +112,7 @@ namespace MP.IOC.Services recordsToInsert.Add(new StatsAggregatedModel { Hour = hourFromKey.Date.AddHours(hourFromKey.Hour), - Envir = parts.Length > 4 ? parts[4] : "unknown", + Destination = parts.Length > 4 ? parts[4] : "unknown", RequestCount = (long)score.Value, AvgDuration = 0, MinDuration = 0, @@ -142,7 +135,7 @@ namespace MP.IOC.Services for (int i = 0; i < sampleCount; i++) { var r = recordsToInsert[i]; - Log.Info($"[HISTORICAL SAMPLE] Hour={r.Hour:yyyy-MM-dd HH:mm}, Envir={r.Envir}, Count={r.RequestCount}"); + Log.Info($"[HISTORICAL SAMPLE] Hour={r.Hour:yyyy-MM-dd HH:mm}, Destination={r.Destination}, Count={r.RequestCount}"); } } } @@ -174,7 +167,7 @@ namespace MP.IOC.Services { recordsToInsert.Add(new StatsDetailModel { - Envir = parts.Length > 4 ? parts[4] : "unknown", + Destination = parts.Length > 4 ? parts[4] : "unknown", Type = method, Hour = dayFromKey.Date, RequestCount = (long)score.Value, @@ -200,7 +193,7 @@ namespace MP.IOC.Services { var r = recordsToInsert[i]; Log.Info("[HISTORICAL SAMPLE] Env={env}, Type={type}, Date={date}, Count={count}", - r.Envir, r.Type, r.Hour.ToString("yyyy-MM-dd"), r.RequestCount); + r.Destination, r.Type, r.Hour.ToString("yyyy-MM-dd"), r.RequestCount); } } } @@ -237,7 +230,23 @@ namespace MP.IOC.Services foreach (var kv in snapshot) { - var method = kv.Key; + string dest = "IO"; + string method = "NA"; + // verifico se ho chiave completo (dest+method) o parziale + string rawKey = kv.Key; + if (rawKey.Contains("|")) + { + var splitVal = rawKey.Split("|"); + dest = splitVal[0]; + method = splitVal[1]; + } + else + { + method = rawKey; + } +#if false + var method = kv.Key; +#endif var stat = kv.Value; var count = Interlocked.Read(ref stat.Count); var totalMs = stat.TotalDuration.TotalMilliseconds; @@ -254,7 +263,7 @@ namespace MP.IOC.Services var aggrRecord = new StatsAggregatedModel { Hour = hourStart, - Envir = method, + Destination = dest, RequestCount = count, AvgDuration = avgDuration, MaxDuration = finalMaxMs, @@ -264,6 +273,7 @@ namespace MP.IOC.Services aggrRecords.Add(aggrRecord); +#if false foreach (var destStat in stat.Destinations) { var detailCount = Interlocked.Read(ref destStat.Value.Count); @@ -278,7 +288,7 @@ namespace MP.IOC.Services var detailRecord = new StatsDetailModel { - Envir = destStat.Key, + Destination = destStat.Key, Type = method, Hour = hourStart, RequestCount = detailCount, @@ -290,6 +300,7 @@ namespace MP.IOC.Services detailRecords.Add(detailRecord); } +#endif } await using var scope = _scopeFactory.CreateAsyncScope(); if (aggrRecords.Count > 0) @@ -302,8 +313,8 @@ namespace MP.IOC.Services for (int i = 0; i < sampleCount; i++) { var r = aggrRecords[i]; - Log.Info("[SAMPLE] INSERT Aggregated: Hour={hour}, Envir={Envir}, Count={count}, Avg={avg:F2}ms, Min={min:F2}ms, Max={max:F2}ms", - r.Hour.ToString("yyyy-MM-dd HH:mm"), r.Envir, r.RequestCount, r.AvgDuration, r.MinDuration, r.MaxDuration); + Log.Info("[SAMPLE] INSERT Aggregated: Hour={hour}, Destination={Destination}, Count={count}, Avg={avg:F2}ms, Min={min:F2}ms, Max={max:F2}ms", + r.Hour.ToString("yyyy-MM-dd HH:mm"), r.Destination, r.RequestCount, r.AvgDuration, r.MinDuration, r.MaxDuration); } } @@ -318,7 +329,7 @@ namespace MP.IOC.Services { var r = detailRecords[i]; Log.Info("[SAMPLE] INSERT Detail: Env={env}, Type={type}, Hour={hour}, Count={count}, Avg={avg:F2}ms, Min={min:F2}ms, Max={max:F2}ms", - r.Envir, r.Type, r.Hour.ToString("yyyy-MM-dd HH:mm"), r.RequestCount, r.AvgDuration, r.MinDuration, r.MaxDuration); + r.Destination, r.Type, r.Hour.ToString("yyyy-MM-dd HH:mm"), r.RequestCount, r.AvgDuration, r.MinDuration, r.MaxDuration); } } diff --git a/MP.IOC/Services/RouteManager.cs b/MP.IOC/Services/RouteManager.cs index 98b58120..d51a57d6 100644 --- a/MP.IOC/Services/RouteManager.cs +++ b/MP.IOC/Services/RouteManager.cs @@ -102,8 +102,10 @@ namespace MP.IOC.Services try { +#if false // Registra scelta - _stats.Record(metodo, target); + _stats.Record(metodo, target); +#endif // imposta la Path che vogliamo che YARP appenda al destBase context.Request.Path = new PathString("/" + relativePath); @@ -116,7 +118,11 @@ namespace MP.IOC.Services var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, requestOptions, _transformer, context.RequestAborted); sw.Stop(); - _stats.RecordDuration(metodo, sw.Elapsed); + string sKey = $"{target}|{metodo}"; + _stats.RecordDuration(sKey, sw.Elapsed); +#if false + _stats.RecordDuration(metodo, sw.Elapsed); +#endif if (error != ForwarderError.None) { diff --git a/MP.IOC/Services/RouteStatsManager.cs b/MP.IOC/Services/RouteStatsManager.cs index d8060484..756a2f54 100644 --- a/MP.IOC/Services/RouteStatsManager.cs +++ b/MP.IOC/Services/RouteStatsManager.cs @@ -8,39 +8,56 @@ namespace MP.IOC.Services public TimeSpan TotalDuration = TimeSpan.Zero; public TimeSpan MaxDuration = TimeSpan.Zero; public TimeSpan MinDuration = TimeSpan.MaxValue; - public ConcurrentDictionary Destinations = new(); +#if false + public ConcurrentDictionary Destinations = new(); +#endif public ConcurrentDictionary StatusCodes = new(); } +#if false public class DestinationStats { public long Count; public TimeSpan TotalDuration = TimeSpan.Zero; public TimeSpan MaxDuration = TimeSpan.Zero; public TimeSpan MinDuration = TimeSpan.MaxValue; - } + } +#endif public class RouteStatsManager { private readonly ConcurrentDictionary _map = new(); +#if false + /// + /// Registrazione del metodo + destinazione + /// + /// + /// public void Record(string method, string destination) { var stat = _map.GetOrAdd(method, _ => new RouteStats()); Interlocked.Increment(ref stat.Count); - + var destStat = stat.Destinations.GetOrAdd(destination, _ => new DestinationStats()); Interlocked.Increment(ref destStat.Count); - } + } +#endif - public void RecordDuration(string method, TimeSpan duration) + /// + /// Registrazione destinazione+metodo + /// + /// chiave dest+metodo x salvataggio statistiche + /// + public void RecordDuration(string dest_method, TimeSpan duration) { - if (_map.TryGetValue(method, out var stat)) + if (_map.TryGetValue(dest_method, out var stat)) { lock (stat) { + stat.Count += 1; stat.TotalDuration += duration; - + if (stat.MaxDuration < duration) { stat.MaxDuration = duration; @@ -50,12 +67,13 @@ namespace MP.IOC.Services stat.MinDuration = duration; } +#if false foreach (var destStat in stat.Destinations.Values) { lock (destStat) { destStat.TotalDuration += duration; - + if (destStat.MaxDuration < duration) { destStat.MaxDuration = duration; @@ -65,7 +83,8 @@ namespace MP.IOC.Services destStat.MinDuration = duration; } } - } + } +#endif } } } diff --git a/MP.IOC/appsettings.json b/MP.IOC/appsettings.json index d9d6acac..a3a23dfb 100644 --- a/MP.IOC/appsettings.json +++ b/MP.IOC/appsettings.json @@ -70,8 +70,8 @@ } }, "RouteMan": { - "FlushIntervalSeconds": 10, - //"FlushIntervalSeconds": 60, + "MetricCalcIntervalSeconds": 10, + "MetricFlushIntervalSeconds": 60, "DefaultWeightOld": 100, "DefaultWeightNew": 0, "DeleteExpiredMetrics": false