Aggiunta metodo x snapshot quotdiani FluxLog

This commit is contained in:
Samuele Locatelli
2026-04-16 08:17:34 +02:00
parent b0e960be84
commit 6d2d1603af
4 changed files with 356 additions and 130 deletions
+3
View File
@@ -24,10 +24,13 @@ namespace MP.Core
public const string redisDecNumArtKey = redisBaseAddr + "Cache:DecNumArt";
public const string redisDossByMac = redisBaseAddr + "Cache:DossByMac";
public const string redisDossByMacLast = redisBaseAddr + "Cache:DossByMacLast";
public const string redisEventList = redisBaseAddr + "Cache:EventList";
public const string redisFluxByMac = redisBaseAddr + "Cache:FluxByMac";
public const string redisFluxByMacFirst = redisBaseAddr + "Cache:FluxByMacFirst";
public const string redisConfFlux = redisBaseAddr + "Cache:ConfFlux";
public const string redisFluxLogFilt = redisBaseAddr + "Cache:FluxLogFilt";
+87 -19
View File
@@ -55,6 +55,7 @@ namespace MP.Data.Controllers
}
return fatto;
}
/// <summary>
/// Restituisce l'anagrafica STATI per intero
/// </summary>
@@ -73,21 +74,21 @@ namespace MP.Data.Controllers
}
/// <summary>
/// Elenco tabella decodifica articoli / codice decimale
/// Record ConfFlux dato macchina (oppure tutti se vuoto)
/// </summary>
/// <param name="codArt">Vuoto = tutti / Singolo CodArt</param>
/// <param name="idxMacc"></param>
/// <returns></returns>
public async Task<List<DecNumArticoliModel>> DecNumArtGetFiltAsync(string codArt = "")
public async Task<List<ConfFluxModel>> ConfFluxFiltAsync(string idxMacc)
{
List<DecNumArticoliModel> dbResult = new List<DecNumArticoliModel>();
using (var dbCtx = new MoonProContext(_configuration))
List<ConfFluxModel> dbResult = new();
using (var dbCtx = new MoonPro_FluxContext(_configuration))
{
var query = dbCtx.DbSetDecNumArt
var query = dbCtx.DbSetConfFlux
.AsNoTracking()
.AsQueryable();
if (!string.IsNullOrEmpty(codArt))
query = query.Where(x => x.CodArticolo == codArt);
if (!string.IsNullOrEmpty(idxMacc))
query = query.Where(x => x.IdxMacchina == idxMacc);
dbResult = await query.ToListAsync();
}
@@ -153,6 +154,7 @@ namespace MP.Data.Controllers
}
return dbResult;
}
/// <summary>
/// Intera tab dati macchina
/// </summary>
@@ -205,11 +207,54 @@ namespace MP.Data.Controllers
return fatto;
}
/// <summary>
/// Elenco tabella decodifica articoli / codice decimale
/// </summary>
/// <param name="codArt">Vuoto = tutti / Singolo CodArt</param>
/// <returns></returns>
public async Task<List<DecNumArticoliModel>> DecNumArtGetFiltAsync(string codArt = "")
{
List<DecNumArticoliModel> dbResult = new List<DecNumArticoliModel>();
using (var dbCtx = new MoonProContext(_configuration))
{
var query = dbCtx.DbSetDecNumArt
.AsNoTracking()
.AsQueryable();
if (!string.IsNullOrEmpty(codArt))
query = query.Where(x => x.CodArticolo == codArt);
dbResult = await query.ToListAsync();
}
return dbResult;
}
public void Dispose()
{
_configuration = null;
}
/// <summary>
/// Stored x recuperare ultimi dossier macchina
/// </summary>
/// <param name="idxMacc"></param>
/// <returns></returns>
public async Task<List<DossierModel>> DossGetLastByMaccAsync(string idxMacc)
{
List<DossierModel> dbResult = new();
using (var dbCtx = new MoonPro_FluxContext(_configuration))
{
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc);
dbResult = await dbCtx
.DbSetDossiers
.FromSqlRaw("exec dbo.stp_DOSS_getLastByMacch @idxMacchina", IdxMacchina)
.AsNoTracking()
.ToListAsync();
}
return dbResult;
}
/// <summary>
/// Aggiunta record EventList
/// </summary>
@@ -260,6 +305,29 @@ namespace MP.Data.Controllers
return fatto;
}
/// <summary>
/// Chiamata x stored recupero FluxLog x macchina (first)
/// </summary>
/// <param name="idxMacc"></param>
/// <param name="numMax"></param>
/// <returns></returns>
public async Task<List<FluxLogModel>> FluxLogFirstByMaccAsync(string idxMacc, int numMax)
{
List<FluxLogModel> dbResult = new();
using (var dbCtx = new MoonPro_FluxContext(_configuration))
{
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc);
var NumMax = new SqlParameter("@numMax", numMax);
dbResult = await dbCtx
.DbSetFluxLog
.FromSqlRaw("exec dbo.stp_FL_getFirstByMacc @IdxMacchina, @numMax", IdxMacchina, NumMax)
.AsNoTracking()
.ToListAsync();
}
return dbResult;
}
/// <summary>
/// Elenco ultimi n record flux log dato macchina e flusso (ordinato x data registrazione)
/// </summary>
@@ -336,25 +404,25 @@ namespace MP.Data.Controllers
}
/// <summary>
/// Record ConfFlux dato macchina (oppure tutti se vuoto)
/// Stored x eseguire Snapshot FluxLog (= Dossier) dato periodo
/// </summary>
/// <param name="idxMacc"></param>
/// <returns></returns>
public async Task<List<ConfFluxModel>> ConfFluxFiltAsync(string idxMacc)
public async Task<bool> FluxLogTakeSnapshotLastAsync(string idxMacc, DateTime dataInizio, DateTime dataFine)
{
List<ConfFluxModel> dbResult = new();
bool fatto = false;
using (var dbCtx = new MoonPro_FluxContext(_configuration))
{
var query = dbCtx.DbSetConfFlux
.AsNoTracking()
.AsQueryable();
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc);
var DataInizio = new SqlParameter("@DtMin", dataInizio);
var DataFine = new SqlParameter("@DtMax", dataFine);
if (!string.IsNullOrEmpty(idxMacc))
query = query.Where(x => x.IdxMacchina == idxMacc);
dbResult = await query.ToListAsync();
var result = await dbCtx
.Database
.ExecuteSqlRawAsync("EXEC stp_FL_TakeSnapshotLast @IdxMacchina, @DtMin, @DtMax", IdxMacchina, DataInizio, DataFine);
fatto = result > 0;
}
return dbResult;
return fatto;
}
public bool KeepAliveUpsert(string IdxMacc, DateTime OraServer, DateTime OraMacc)
+52 -109
View File
@@ -103,7 +103,6 @@ namespace MP.IOC.Controllers
}
}
/// <summary>
/// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI)
/// POST: IOB/evListJson/SIMUL_03
@@ -136,7 +135,6 @@ namespace MP.IOC.Controllers
return Ok(answ);
}
#if false
/// <summary>
/// Sistema Dossier/Snapshot giornalieri x impianto indicato, andando a generare 1 Dossier
/// giornaliero x ogni giornata dall'ultimo registrato alla data corrente
@@ -144,80 +142,25 @@ namespace MP.IOC.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public string fixDailyDossier(string id)
[HttpGet("fixDailyDossier/{id}")]
public async Task<IActionResult> FixDailyDossier(string id)
{
string answ = "";
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID");
// Multi: gestione carattere "|" trasformato in "#"
id = id.Replace("|", "#");
// effettuo processing
string answ = "";
try
{
DataLayer DataLayerObj = new DataLayer();
// verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata...
var confDataMach = DataLayerObj.confFluxMach(id);
if (confDataMach.Count > 0)
{
// determino ultima data da processare (inizio oggi, a mezzanotte)
DateTime dtTo = DateTime.Today;
DateTime dtFrom = dtTo;
// determino data di partenza, prima da dossier esistenti
var listaDoss = DataLayerObj.dossierLastByMach(id);
if (listaDoss.Count > 0)
{
// primo giorno DOPO ultima registrazione
dtFrom = listaDoss.OrderByDescending(x => x).FirstOrDefault().AddDays(1);
}
else
{
// ...o da fluxLog acquisiti...
var listaFL = DataLayerObj.fluxLogFirstByMach(id);
if (listaFL.Count > 0)
{
// giorno successivo a prima registrazione
dtFrom = listaFL.OrderBy(x => x).FirstOrDefault().AddDays(1);
}
}
string caller = $"takeFlogSnapshot({id})";
DateTime dtStart = dtFrom.Date;
DateTime dtEnd = dtFrom;
// max 10 dossier alla volta (se non configurato diversamente)
int maxAdd = memLayer.ML.CRI("IO_numDossMaxCreate");
if (dtStart < dtTo)
{
// verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le
// date da processare
while (dtStart < dtTo && maxAdd > 0)
{
// sistemo end
dtEnd = dtStart.AddDays(1);
// effettuo chiamata registrazione snapshot!
answ = doSaveFLSnapshot(id, dtStart, dtEnd, caller);
// incremento START...
dtStart = dtEnd;
// riduco il numero di chiamate ammesse x singolo task
maxAdd--;
}
// reset cache dossier...
DataLayerObj.dossierLastByMachReset(id);
}
else
{
answ = "NO more to add";
}
}
else
{
answ = "NO ConfFluxData";
}
answ = await DService.FixDailyDossierAsync(id);
}
catch (Exception exc)
{
logger.lg.scriviLog($"Eccezione in recupero fixDailyDossier{Environment.NewLine}{exc}", tipoLog.EXCEPTION);
Log.Error($"Errore in FixDailyDossier{Environment.NewLine}{exc}");
return StatusCode(StatusCodes.Status500InternalServerError, "NO");
}
return answ;
}
#endif
return Ok(answ);
}
/// <summary>
/// Sistema ODL giornalieri x impianto indicato, andando a generare 1 ODL giornaliero x ogni
@@ -1237,6 +1180,47 @@ namespace MP.IOC.Controllers
#region Private Methods
/// <summary>
/// Processing effettivo EvListJson
/// </summary>
/// <param name="idxMacc"></param>
/// <param name="content"></param>
/// <returns></returns>
private async Task<string> processEvListJsonAsync(string idxMacc, string content)
{
string answ = "";
int insDone = 0;
// procedo a deserializzare in blocco l'oggetto...
EvJsonPayloadDto receivedData = JsonConvert.DeserializeObject<EvJsonPayloadDto>(content) ?? new();
// se ho qualcosa da processare...
if (receivedData != null)
{
// per ogni valore --> processo!
try
{
foreach (var item in receivedData.eventList)
{
// formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000
answ = await DService.ProcessInputAsync(idxMacc, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt.ToString());
insDone++;
}
// se vuoto --> OK!
if (string.IsNullOrEmpty(answ))
{
answ = $"OK {insDone} processed";
}
}
catch (Exception exc)
{
Log.Error($"Errore in fase invio valori inputJson{Environment.NewLine}{exc}");
answ = "NO";
}
}
return answ;
}
/// <summary>
/// Effettivo processing FLogJson
/// </summary>
@@ -1349,47 +1333,6 @@ namespace MP.IOC.Controllers
return answ;
}
/// <summary>
/// Processing effettivo EvListJson
/// </summary>
/// <param name="idxMacc"></param>
/// <param name="content"></param>
/// <returns></returns>
private async Task<string> processEvListJsonAsync(string idxMacc, string content)
{
string answ = "";
int insDone = 0;
// procedo a deserializzare in blocco l'oggetto...
EvJsonPayloadDto receivedData = JsonConvert.DeserializeObject<EvJsonPayloadDto>(content) ?? new();
// se ho qualcosa da processare...
if (receivedData != null)
{
// per ogni valore --> processo!
try
{
foreach (var item in receivedData.eventList)
{
// formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000
answ = await DService.ProcessInputAsync(idxMacc, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt.ToString());
insDone++;
}
// se vuoto --> OK!
if (string.IsNullOrEmpty(answ))
{
answ = $"OK {insDone} processed";
}
}
catch (Exception exc)
{
Log.Error($"Errore in fase invio valori inputJson{Environment.NewLine}{exc}");
answ = "NO";
}
}
return answ;
}
/// <summary>
/// Effettua processing UserLog
/// </summary>
+214 -2
View File
@@ -946,6 +946,80 @@ namespace MP.IOC.Data
return fatto;
}
/// <summary>
/// Task completo sistemazione dossier quotidiani mancanti
/// </summary>
/// <param name="idxMacc"></param>
/// <returns></returns>
public async Task<string> FixDailyDossierAsync(string idxMacc)
{
string answ = "";
// verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata...
var confDataMach = await ConfFluxMach(idxMacc);
if (confDataMach.Count > 0)
{
// determino ultima data da processare (inizio oggi, a mezzanotte)
DateTime dtTo = DateTime.Today;
DateTime dtFrom = dtTo;
// determino data di partenza, prima da dossier esistenti
var listaDoss = await DossierLastByMachAsync(idxMacc);
if (listaDoss.Count > 0)
{
// primo giorno DOPO ultima registrazione
dtFrom = listaDoss.OrderByDescending(x => x).FirstOrDefault().AddDays(1);
}
else
{
// ...o da fluxLog acquisiti...
var listaFL = await FluxLogFirstByMachAsync(idxMacc);
if (listaFL.Count > 0)
{
// giorno successivo a prima registrazione
dtFrom = listaFL.OrderBy(x => x).FirstOrDefault().AddDays(1);
}
}
string caller = $"takeFlogSnapshot({idxMacc})";
DateTime dtStart = dtFrom.Date;
DateTime dtEnd = dtFrom;
// max 10 dossier alla volta (se non configurato diversamente)
int maxAdd = 1;
string confVal = await tryGetConfig("IO_numDossMaxCreate");
if (!string.IsNullOrEmpty(confVal))
{
int.TryParse(confVal, out maxAdd);
}
if (dtStart < dtTo)
{
// verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le
// date da processare
while (dtStart < dtTo && maxAdd > 0)
{
// sistemo end
dtEnd = dtStart.AddDays(1);
// effettuo chiamata registrazione snapshot!
answ = await FluxLogSaveSnapshotAsync(idxMacc, dtStart, dtEnd, caller);
// incremento START...
dtStart = dtEnd;
// riduco il numero di chiamate ammesse x singolo task
maxAdd--;
}
// reset cache dossier...
await DossierLastByMachResetAsync(idxMacc);
answ = "OK";
}
else
{
Log.Warn("FixDailyDossierAsync | NO more to add");
}
}
else
{
Log.Warn("FixDailyDossierAsync | NO ConfFluxData");
}
return answ;
}
public async Task<bool> FlushRedisCache()
{
await Task.Delay(1);
@@ -1209,7 +1283,7 @@ namespace MP.IOC.Data
/// <summary>
/// </summary>
/// <param name="IdxOdl">id odl da cercare</param>
/// <param name="IdxOdl">idxMacc odl da cercare</param>
/// <returns></returns>
public async Task<List<AnagGiacenzeModel>> ListGiacenze(int IdxOdl)
{
@@ -1385,7 +1459,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Elenco id Macchine che abbiano dati FLuxLog, nel periodo indicato
/// Elenco idxMacc Macchine che abbiano dati FLuxLog, nel periodo indicato
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
@@ -3880,6 +3954,144 @@ namespace MP.IOC.Data
}
}
/// <summary>
/// Restituisce l'elenco codici flusso (da confFlux) x una macchina (se presenti) Impiegata
/// anche cache redis
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
private async Task<List<string>> ConfFluxMach(string idxMacchina)
{
List<string> resultList = new List<string>();
string tag = string.IsNullOrEmpty(idxMacchina) ? "ALL" : idxMacchina;
var currKey = $"{Utils.redisConfFlux}:{tag}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
resultList = JsonConvert.DeserializeObject<List<string>>($"{rawData}") ?? new();
}
else
{
var dbData = await IocDbController.ConfFluxFiltAsync(idxMacchina);
resultList = dbData
.Select(x => x.CodFlux)
.ToList();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(resultList);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (resultList == null)
{
resultList = new();
}
return resultList;
}
/// <summary>
/// Restituisce l'elenco delle date dei dossier x una macchina (se presenti) Impiegata anche
/// cache redis
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
private async Task<List<DateTime>> DossierLastByMachAsync(string idxMacchina)
{
List<DateTime> resultList = new List<DateTime>();
var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
resultList = JsonConvert.DeserializeObject<List<DateTime>>($"{rawData}") ?? new();
}
else
{
var dbData = await IocDbController.DossGetLastByMaccAsync(idxMacchina);
resultList = dbData
.Select(x => x.DtRif)
.ToList();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(resultList);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (resultList == null)
{
resultList = new List<DateTime>();
}
return resultList;
}
/// <summary>
/// Svuota la cache redis x l'elenco delle righe di confFlux x una macchina (se presenti)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
private async Task<bool> DossierLastByMachResetAsync(string idxMacchina)
{
bool answ = false;
var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
await redisDb.KeyDeleteAsync(currKey);
return answ;
}
/// <summary>
/// Restituisce l'elenco delle data-ora di confFlux x una macchina (se presenti) Impiegata
/// anche cache redis
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="numMax">num record da recuperare</param>
/// <returns></returns>
private async Task<List<DateTime>> FluxLogFirstByMachAsync(string idxMacchina, int numMax = 10)
{
List<DateTime> resultList = new List<DateTime>();
var currKey = $"{Utils.redisFluxByMacFirst}:{idxMacchina}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
resultList = JsonConvert.DeserializeObject<List<DateTime>>($"{rawData}") ?? new();
}
else
{
var dbData = await IocDbController.FluxLogFirstByMaccAsync(idxMacchina, numMax);
resultList = dbData
.Select(x => x.dtEvento)
.ToList();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(resultList);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (resultList == null)
{
resultList = new List<DateTime>();
}
return resultList;
}
/// <summary>
/// Effettua vera chiamata x salvataggio snapshot dati FluxLog
/// </summary>
/// <param name="id"></param>
/// <param name="maxSec"></param>
/// <param name="caller"></param>
/// <returns></returns>
private async Task<string> FluxLogSaveSnapshotAsync(string id, DateTime dtStart, DateTime dtEnd, string caller)
{
string answ = "";
DateTime dataOraEvento = DateTime.Now;
Log.Debug($"{caller} | Richiesta snapshot dati FluxLog macchina: id: {id} | periodo: {dtStart} - {dtEnd}");
try
{
bool fatto = await IocDbController.FluxLogTakeSnapshotLastAsync(id, dtStart, dtEnd);
answ = fatto ? "OK" : "KO";
}
catch (Exception exc)
{
Log.Error($"Errore in {caller}{Environment.NewLine}{exc}");
answ = "NO";
}
return answ;
}
/// <summary>
/// Recupero info ODL corrente da dati prod macchina
/// </summary>