Update metodi x insert async in transazione

This commit is contained in:
Samuele Locatelli
2026-04-29 17:25:05 +02:00
parent 8860f5687c
commit bfd843cfde
3 changed files with 343 additions and 225 deletions
+54
View File
@@ -372,6 +372,60 @@ namespace MP.Data.Controllers
return await dbCtx.SaveChangesAsync() > 0;
}
/// <summary>
/// Aggiunta record MicroStato + EventList
/// </summary>
/// <param name="newRecMsm"></param>
/// <param name="newRecEv"></param>
/// <returns></returns>
public async Task<bool> EvListMicroStatoInsertAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
{
// eseguo in transazione...
await using var dbCtx = new MoonProContext(_configuration);
await using var tx = await dbCtx.Database.BeginTransactionAsync();
try
{
// inizio con record microstato...
var actRec = await dbCtx
.DbSetMicroStatoMacc
.FindAsync(newRecMsm.IdxMacchina);
//.SingleOrDefaultAsync();
if (actRec == null)
{
dbCtx.DbSetMicroStatoMacc.Add(newRecMsm);
}
else
{
actRec.IdxMicroStato = newRecMsm.IdxMicroStato;
actRec.InizioStato = newRecMsm.InizioStato;
actRec.Value = newRecMsm.Value;
// Update() allega l'entità e segna tutti i campi come Modified
dbCtx.DbSetMicroStatoMacc.Update(actRec);
#if false
dbCtx.Entry(actRec).State = EntityState.Modified;
#endif
}
// ora record EVList
dbCtx.DbSetEvList.Add(newRecEv);
// EF Core 8 raggruppa automaticamente INSERT/UPDATE in un batch
var rowsAffected = await dbCtx.SaveChangesAsync();
await tx.CommitAsync();
return rowsAffected > 0;
}
catch
{
await tx.RollbackAsync();
throw;
}
}
/// <summary>
/// Chiamata x stored recupero FluxLog x macchina (first)
/// </summary>
+1 -1
View File
@@ -131,7 +131,7 @@ namespace MP.IOC.Controllers
}
// recupero singolo valore (stringa) x chiave
outVal = DService.ValoreSMI(idxFamIn, idxMicroStato, valIOB);
outVal = await DService.ValoreSmiAsync(idxFamIn, idxMicroStato, valIOB);
// mostro output
answ += $"idxFamIN: {idxFamIn} | idxMS: {idxMicroStato} | valIOB: {valIOB} | out: {outVal}";
}
+288 -224
View File
@@ -156,9 +156,9 @@ namespace MP.IOC.Data
try
{
Dictionary<string, string> savedTask = mSavedTaskMacchina(idxMacchina);
// cerco valore saved
// cerco valOut saved
string savedVal = savedTask[taskKey.ToString()];
// se ho un valore != "" --> rimetto in coda di invio...
// se ho un valOut != "" --> rimetto in coda di invio...
if (!string.IsNullOrEmpty(savedVal) && (savedVal != taskVal))
{
// leggo tName attuali...
@@ -342,8 +342,8 @@ namespace MP.IOC.Data
/// <param name="idxMacchina">Idx macchina</param>
/// <param name="memAddress">area memoria</param>
/// <param name="memAddress">indice memoria</param>
/// <param name="memAddress">valore status</param>
/// <param name="memAddress">valore decodificato</param>
/// <param name="memAddress">valOut status</param>
/// <param name="memAddress">valOut decodificato</param>
/// <returns></returns>
public async Task<bool> AlarmInsertAsync(DateTime dtRif, string idxMacchina, string memAddress, int memIndex, int statusVal, string valDecoded)
{
@@ -449,7 +449,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = Utils.redisArtByDossier;
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -497,7 +497,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisArtList}:Last:{idxMacc}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -535,7 +535,7 @@ namespace MP.IOC.Data
string readType = "DB";
string sKey = string.IsNullOrEmpty(searchVal) ? "***" : searchVal;
string currKey = $"{Utils.redisArtList}:{azienda}:{sKey}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -947,7 +947,7 @@ namespace MP.IOC.Data
/// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
/// </summary>
/// <param name="idxMacchina">idx macchina</param>
/// <param name="valore">valore ingresso</param>
/// <param name="valore">valOut ingresso</param>
/// <param name="dtEve">data-ora evento (server)</param>
/// <param name="contatore">sequenza dati inviati</param>
/// <param name="datiMaccCache">dati macchina in cache (opzionale, se null fa lookup)</param>
@@ -960,8 +960,11 @@ namespace MP.IOC.Data
// processing
inputComandoMapo answ = new inputComandoMapo();
// verifico se esista la macchina altrimenti la creo... REDIS compliant
await verificaIdxMacchinaAsync(idxMacchina);
// SE no trovassi verifico se esista la macchina altrimenti la creo... REDIS compliant
if (!datiMacc.ContainsKey(idxMacchina))
{
await verificaIdxMacchinaAsync(idxMacchina);
}
// continuo processing...
string CodArticolo = datiMacc["CodArticolo"];
@@ -980,34 +983,31 @@ namespace MP.IOC.Data
int next_idxMS = 0;
try
{
valINT = int.Parse(valore, System.Globalization.NumberStyles.HexNumber);
try
valINT = int.Parse(valore, NumberStyles.HexNumber);
int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]);
int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]);
int valIOB = Convert.ToInt32(valINT);
next_idxMS = idxMicroStato;
#if false
// verifico esistenza tab SMI...
var fiHASH = Utils.GetHashSMI(idxFamIn);
bool trovato = await RedisKeyPresentAsync(fiHASH);
if (!trovato)
{
int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]);
int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]);
int valIOB = Convert.ToInt32(valINT);
next_idxMS = idxMicroStato;
// verifico esistenza tab SMI...
var fiHASH = Utils.GetHashSMI(idxFamIn);
bool trovato = await RedisKeyPresentAsync(fiHASH);
if (!trovato)
{
// ricarico tabella (salvando in redis x ricerca successiva)!
KeyValuePair<string, string>[] valori = await StateMachInByKeyAsync(idxFamIn);
}
string todoSMI = "";
// recupero singolo valore (stringa) x chiave
todoSMI = valoreSMI(idxFamIn, idxMicroStato, valIOB);
// solo se ho trovato un risultato nella tab SMI della famiglia macchina...
if (todoSMI != "")
{
// splitto e salvo valori OUT...
string[] valori = todoSMI.Split('_');
idxTipoEv = Convert.ToInt32(valori[0]);
next_idxMS = Convert.ToInt32(valori[1]);
}
// ricarico tabella (salvando in redis x ricerca successiva)!
KeyValuePair<string, string>[] valori = await StateMachInByKeyAsync(idxFamIn);
}
#endif
// recupero singolo valOut (stringa) x chiave
string todoSMI = await ValoreSmiAsync(idxFamIn, idxMicroStato, valIOB);
// solo se ho trovato un risultato nella tab SMI della famiglia macchina...
if (!string.IsNullOrEmpty(todoSMI) && todoSMI.Contains("_"))
{
// splitto e salvo valori OUT...
string[] valori = todoSMI.Split('_');
idxTipoEv = Convert.ToInt32(valori[0]);
next_idxMS = Convert.ToInt32(valori[1]);
}
catch { }
}
catch (Exception exc)
{
@@ -1015,38 +1015,35 @@ namespace MP.IOC.Data
}
// effettuo update vari SU DB!!!
MicroStatoMacchinaModel newRec = new MicroStatoMacchinaModel()
MicroStatoMacchinaModel newRecMsm = new MicroStatoMacchinaModel()
{
IdxMacchina = idxMacchina,
IdxMicroStato = next_idxMS,
InizioStato = dtEve,
Value = valore
};
await IocDbController.MicroStatoMacchinaUpsertAsync(newRec);
if (idxTipoEv > 0)
{
try
// preparo record
string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore);
// creo evento
EventListModel newRecEv = new EventListModel()
{
// preparo record
string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore);
// creo evento
EventListModel newRecEv = new EventListModel()
{
CodArticolo = CodArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxTipoEv,
InizioStato = dtEve,
MatrOpr = 0,
pallet = "-",
Value = valEsteso
};
// salva e processa
answ = await scriviRigaEventoAsync(newRecEv);
}
catch (Exception exc)
{
Log.Error($"[ChkMiSt_8a] - Eccezione:{Environment.NewLine}{exc}");
}
CodArticolo = CodArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxTipoEv,
InizioStato = dtEve,
MatrOpr = 0,
pallet = "-",
Value = valEsteso
};
// salva e processa evento + microstato
answ = await scriviRigaEventoAsync(newRecMsm, newRecEv);
}
else
{
// solo microstato
await IocDbController.MicroStatoMacchinaUpsertAsync(newRecMsm);
}
return answ;
}
@@ -1112,7 +1109,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisBaseAddr}:TabDatiMacchine:ALL";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1141,7 +1138,7 @@ namespace MP.IOC.Data
List<DecNumArticoliModel> result = new();
string tag = string.IsNullOrEmpty(codArt) ? "ALL" : codArt;
string currKey = $"{Utils.redisDecNumArtKey}:{tag}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
@@ -1234,7 +1231,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisDossByMac}:{IdxMacchina}:{CodArticolo}:{DtStart:yyyyMMddHHmm}:{DtEnd:yyyyMMddHHmm}:{MaxRec}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
@@ -1293,7 +1290,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Update valore dossier
/// Update valOut dossier
/// </summary>
/// <param name="currDoss"></param>
/// <returns></returns>
@@ -1325,7 +1322,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisAnagGruppi}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1443,7 +1440,7 @@ namespace MP.IOC.Data
DateTime dtEnd = dtFrom;
// max 10 dossier alla volta (se non configurato diversamente)
int maxAdd = 1;
string confVal = await tryGetConfig("IO_numDossMaxCreate");
string confVal = await tryGetConfigAsync("IO_numDossMaxCreate");
if (!string.IsNullOrEmpty(confVal))
{
int.TryParse(confVal, out maxAdd);
@@ -1536,7 +1533,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisFluxLogFilt}:{IdxMacchina}:{CodFlux}:{MaxRec}:{DtMax:yyyyMMddHHmm}:{DtMin:yyyyMMddHHmm}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1550,7 +1547,7 @@ namespace MP.IOC.Data
rawData = JsonConvert.SerializeObject(result);
if (string.IsNullOrEmpty(canCacheParametri))
{
canCacheParametri = await tryGetConfig("SPEC_ParametriEnableRedisCache");
canCacheParametri = await tryGetConfigAsync("SPEC_ParametriEnableRedisCache");
}
if (canCacheParametri != "false")
{
@@ -1568,7 +1565,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
/// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
/// ODL NO invio/gestione ODL)
/// </summary>
/// <param name="idxMacchina"></param>
@@ -1577,7 +1574,7 @@ namespace MP.IOC.Data
{
string result = "";
string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1594,7 +1591,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
/// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
/// ODL NO invio/gestione ODL)
/// </summary>
/// <param name="idxMacchina"></param>
@@ -1620,7 +1617,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore dell'ultimo ODL
/// Restituisce il valOut dell'ultimo ODL
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
@@ -1628,7 +1625,7 @@ namespace MP.IOC.Data
{
ODLExpModel result = new ODLExpModel();
string currKey = $"{Utils.redisOdlLastByMac}:{idxMacchina}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1720,7 +1717,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore booleano se la macchina sia abilitata all'input
/// Restituisce il valOut booleano se la macchina sia abilitata all'input
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
@@ -1740,7 +1737,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore booleano se la macchina sia master
/// Restituisce il valOut booleano se la macchina sia master
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
@@ -1765,7 +1762,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore booleano se la macchina sia abilitata all'inserimento COMPLETO nel
/// Restituisce il valOut booleano se la macchina sia abilitata all'inserimento COMPLETO nel
/// Signal Log
/// </summary>
/// <param name="idxMacchina"></param>
@@ -1807,7 +1804,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisGiacenzaList}:{IdxOdl}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1865,7 +1862,7 @@ namespace MP.IOC.Data
{
List<Macchine2SlaveModel>? result = new List<Macchine2SlaveModel>();
string currKey = $"{Utils.redisBaseAddr}:M2STab";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
@@ -1908,7 +1905,7 @@ namespace MP.IOC.Data
string readType = "DB";
string keyGrp = codGruppo != "*" ? codGruppo : "ALL";
string currKey = $"{Utils.redisMacList}:{keyGrp}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1944,7 +1941,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisMacRecipePath}:{idxMacchina}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -1979,7 +1976,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisMacRecipeConf}:{idxMacchina}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2015,7 +2012,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisMacByFlux}:{dtStart:yyyyMMddHHmm}:{dtEnd:yyyyMMddHHmm}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2151,11 +2148,11 @@ namespace MP.IOC.Data
Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
// leggo i valori attuali...
List<ObjItemDTO> actValues = await MachineParamListAsync(idxMacchina);
// per ogni valore passatomi faccio insert o update rispetto elenco valori correnti
// per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti
// in REDIS
foreach (var item in actValues)
{
// cerco nelle innovazioni SE CI SIA il valore...
// cerco nelle innovazioni SE CI SIA il valOut...
var trovato = innovations.Find(obj => obj.uid == item.uid);
// se non trovato nelle innovazioni...
if (trovato == null)
@@ -2391,7 +2388,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = Utils.redisOdlByBatch;
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2474,7 +2471,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisOdlList}:Current:{IdxMacchina}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
@@ -2521,7 +2518,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisOdlCurrByMac}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2586,7 +2583,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisOdlList}:{inCorso}:{codArt}:{keyRichPart}:{Reparto}:{IdxMacchina}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2622,7 +2619,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisFluxByMac}:{IdxMacchina}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2688,7 +2685,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisPOdlByPOdl}:{idxPODL}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2768,7 +2765,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisPOdlByOdl}:{idxODL}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2818,7 +2815,7 @@ namespace MP.IOC.Data
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisPOdlList}:{codGruppo}:{idxMacchina}:{keyRichPart}:{lanciato}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
// cerco in redis dato valore sel macchina...
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
@@ -2881,7 +2878,7 @@ namespace MP.IOC.Data
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(valore))
{
string errore = "processFluxLog | Errore: parametri macchina/valore vuoti";
string errore = "processFluxLog | Errore: parametri macchina/valOut vuoti";
Log.Error(errore);
answ = errore;
}
@@ -2896,7 +2893,7 @@ namespace MP.IOC.Data
Cnt = contatore
};
await IocDbController.FluxLogInsertAsync(newRec);
// 2022.06.06 salvo su redis il valore ULTIMO del flux x recupero rapido ultimo valore
// 2022.06.06 salvo su redis il valOut ULTIMO del flux x recupero rapido ultimo valOut
var currKey = Utils.RedKeyLastFLog(idxMacchina, flux, MpIoNS);
// 10 min cache max...
await redisDb.StringSetAsync(currKey, valore, TimeSpan.FromMinutes(10));
@@ -2907,6 +2904,89 @@ namespace MP.IOC.Data
return answ;
}
/// <summary>
/// Validazione preliminare valori input
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="valore"></param>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <returns></returns>
private bool ValidateinputParams(string idxMacchina, string valore, string dtEve, string dtCurr)
{
bool isValid = false;
// preparo stringa valori correnti
string currVals = $"idxMacchina: {idxMacchina} | valOut: {valore} | dtEve: {dtEve} | dtCurr:{dtCurr}";
if (dtEve == null || dtCurr == null)
{
Log.Warn($"procInput: null found | {currVals}");
}
else if (dtEve.Length < 17 || dtCurr.Length < 17)
{
Log.Info($"procInput: invalid data | {currVals}");
}
else if (string.IsNullOrEmpty(idxMacchina))
{
Log.Info($"procInput: missing IdxMacchina | {currVals}");
}
else if (string.IsNullOrEmpty(valore))
{
Log.Info($"procInput: missing valOut | {currVals}");
}
else
{
isValid = true;
}
return isValid;
}
/// <summary>
/// Calcola dataora evento da info dt ricevute
/// </summary>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <returns></returns>
private DateTime ParseEventTime(string dtEve, string dtCurr)
{
DateTime dataOraEvento = DateTime.Now;
// fix formato dataora in ingresso
string stdEve = dtFormStd(dtEve);
string stdCurr = dtFormStd(dtCurr);
// 2. Se le stringhe normalizzate coincidono, skip dei calcoli
if (stdEve != stdCurr)
{
// 3. Parsing sicuro
if (DateTime.TryParseExact(stdEve, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtEvento) &&
DateTime.TryParseExact(stdCurr, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtCorrente))
{
TimeSpan diff = dtCorrente - dtEvento;
double ms = Math.Abs(diff.TotalMilliseconds);
// 4. Classificazione delta con switch expression (più leggibile e performante)
string deltaClass = ms switch
{
<= 10 => "0-10 ms",
<= 100 => "10-100 ms",
<= 1000 => "100-1000 ms",
<= 10000 => "1-10 sec",
_ => "> 10 sec"
};
Log.Debug($"Correzione delta {deltaClass}");
// 5. Correzione data/ora server: sottrao lo scarto calcolato
dataOraEvento = dataOraEvento.Subtract(diff);
}
else
{
Log.Error($"Errore parsing date: {stdEve} | {stdCurr}");
}
}
return dataOraEvento;
}
/// <summary>
/// Processa input da IOB eventualmente registrando i segnali inviati
/// </summary>
@@ -2919,118 +2999,55 @@ namespace MP.IOC.Data
public async Task<string> ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
{
string answ = "";
// 2018.10.26 controllo dtEve e dtCurr
if (dtEve == null || dtCurr == null)
if (ValidateinputParams(idxMacchina, valore, dtEve, dtCurr))
{
Log.Warn(string.Format("procInput: valori nulli date: idxMacchina: {0} | valore: {1} | dtEve: {2} | dtCurr:{3}", idxMacchina, valore, dtEve, dtCurr));
}
else if (dtEve.Length < 17 || dtCurr.Length < 17)
{
Log.Info(string.Format("procInput: valori data non corretti: idxMacchina: {0} | valore: {1} | dtEve: {2} | dtCurr:{3}", idxMacchina, valore, dtEve, dtCurr));
}
else
{
DateTime dataOraEvento = DateTime.Now;
DateTime dataOraEvento = ParseEventTime(dtEve, dtCurr);
// fix formato dataora in ingresso
string stdEve = dtFormStd(dtEve);
string stdCurr = dtFormStd(dtCurr);
// 2. Se le stringhe normalizzate coincidono, skip dei calcoli
if (stdEve != stdCurr)
// se abilitato registro evento sul DB
if (await IobSLogEnabAsync(idxMacchina))
{
// 3. Parsing sicuro
if (DateTime.TryParseExact(stdEve, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtEvento) &&
DateTime.TryParseExact(stdCurr, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtCorrente))
int cntVal = 0;
int.TryParse(contatore, out cntVal);
await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
}
// continuo col resto
try
{
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
// Cache dati macchina per evitare lookup ridondanti
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
// verifico se sia una macchina MULTI....
if (isMulti(idxMacchina, datiMacc))
{
TimeSpan diff = dtCorrente - dtEvento;
double ms = Math.Abs(diff.TotalMilliseconds);
// 4. Classificazione delta con switch expression (più leggibile e performante)
string deltaClass = ms switch
// inizio preprocessing
string newVal = "";
// processo OGNI macchina a stati dell'impianto... (KEY:IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn)
foreach (var item in await mTabMSMIAsync(idxMacchina))
{
<= 10 => "0-10 ms",
<= 100 => "10-100 ms",
<= 1000 => "100-1000 ms",
<= 10000 => "1-10 sec",
_ => "> 10 sec"
};
Log.Debug($"Correzione delta {deltaClass}");
// 5. Correzione data/ora server: sottrao lo scarto calcolato
dataOraEvento = dataOraEvento.Subtract(diff);
newVal = preProcInput(item.Key, valore, datiMacc);
// ora processo e salvo il valOut del microstato...
// INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore, datiMacc);
}
}
else
{
Log.Error($"Errore parsing date: {stdEve} | {stdCurr}");
// ora processo e salvo il valOut del microstato... INTERNAMENTE
// gestisce i casi DB/REDIS secondo necessità
await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc);
}
// forzo RESET dati macchina...
await ResetDatiMacchinaAsync(idxMacchina);
// registro in risposta che è andato tutto bene...
answ = "OK";
}
// inizio processing vero e proprio INPUT...
if (string.IsNullOrEmpty(idxMacchina))
catch (Exception exc)
{
string errore = "Errore: missing IdxMacchina";
Log.Warn(errore);
string errore = $"Errore: {Environment.NewLine}{exc}";
Log.Error(errore);
answ = errore;
}
else
{
if (string.IsNullOrEmpty(valore))
{
string errore = "Errore: missing valore";
Log.Warn(errore);
answ = errore;
}
else
{
// se abilitato registro evento sul DB
if (await IobSLogEnabAsync(idxMacchina))
{
int cntVal = 0;
int.TryParse(contatore, out cntVal);
await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
}
// continuo col resto
try
{
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
// Cache dati macchina per evitare lookup ridondanti
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
// verifico se sia una macchina MULTI ed in tal caso calcolo i
// SUB-systems e CHIAMERO' alla fine pure loro....
if (isMulti(idxMacchina, datiMacc))
{
// inizio preprocessing
string newVal = "";
// processo OGNI macchina a stati dell'impianto... (KEY:IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn)
foreach (var item in await mTabMSMIAsync(idxMacchina))
{
newVal = preProcInput(item.Key, valore, datiMacc);
// ora processo e salvo il valore del microstato...
// INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore, datiMacc);
}
}
else
{
// ora processo e salvo il valore del microstato... INTERNAMENTE
// gestisce i casi DB/REDIS secondo necessità
await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc);
}
// forzo RESET dati macchina...
await ResetDatiMacchinaAsync(idxMacchina);
// registro in risposta che è andato tutto bene...
answ = "OK";
}
catch (Exception exc)
{
string errore = $"Errore: {Environment.NewLine}{exc}";
Log.Error(errore);
answ = errore;
}
}
}
}
return answ;
}
@@ -3040,7 +3057,7 @@ namespace MP.IOC.Data
/// </summary>
/// <param name="idxMacchina">Macchina</param>
/// <param name="flux">Flusso: DI/RC/RC</param>
/// <param name="valore">valore = note/valString</param>
/// <param name="valore">valOut = note/valString</param>
/// <param name="dtEve">data evento</param>
/// <param name="dtCurr">data corrente</param>
/// <param name="contatore">contatore invio</param>
@@ -3386,9 +3403,9 @@ namespace MP.IOC.Data
return result;
}
public string RedisGetHashField(RedisKey key, string hashField)
public async Task<RedisValue> RedisGetHashFieldAsync(RedisKey key, string hashField)
{
return redisDb.HashGet(key, hashField).ToString();
return await redisDb.HashGetAsync(key, hashField);
}
public bool RedisKeyPresent(RedisKey key)
@@ -3456,7 +3473,7 @@ namespace MP.IOC.Data
doClean = true;
}
string confVal = await tryGetConfig("IO_NumReboot2Keep");
string confVal = await tryGetConfigAsync("IO_NumReboot2Keep");
int num2keep = int.TryParse(confVal, out int n) ? n : 5;
// insert del record + pulizia
bool fatto = await IocDbController.RemRebootLogAddAndCleanAsync(newRec, doClean, num2keep);
@@ -3591,7 +3608,7 @@ namespace MP.IOC.Data
i++;
}
// verifico il timeout (default 60 sec...)
var sTOutSmi = await tryGetConfig("TmOut.MSMI");
var sTOutSmi = await tryGetConfigAsync("TmOut.MSMI");
int tOut = 60;
int.TryParse(sTOutSmi, out tOut);
tOut = tOut <= 60 ? 60 : tOut;
@@ -3822,7 +3839,7 @@ namespace MP.IOC.Data
/// salva il segnale di "microstato" (segnale) ASYNC
/// </summary>
/// <param name="idxMacchina">idx macchina</param>
/// <param name="valore">valore ingresso</param>
/// <param name="valore">valOut ingresso</param>
/// <param name="dtEve">data-ora evento (server)</param>
/// <param name="contatore">contatore sequenza dati inviati</param>
/// <returns></returns>
@@ -3847,16 +3864,14 @@ namespace MP.IOC.Data
/// <returns></returns>
public async Task ScriviKeepAliveAsync(string IdxMacchina, DateTime oraMacchina)
{
string nomeVar = string.Format("KeepAlive:{0}", IdxMacchina);
// cerco se ho keep alive in redis,
DateTime adesso = DateTime.Now;
var currKey = Utils.RedKeyHash(nomeVar);
var currKey = Utils.RedKeyHash($"KeepAlive:{IdxMacchina}");
bool keyPresent = await RedisKeyPresentAsync(currKey);
// se NON presente salvo in REDIS con TTL 10 sec e sul DB...
if (!keyPresent)
{
await redisDb.StringSetAsync(currKey, adesso.ToString("s"), TimeSpan.FromSeconds(20));
Log.Trace($"Scrittura keep alive! IdxMacchina: {IdxMacchina}");
DateTime adesso = DateTime.Now;
await redisDb.StringSetAsync(currKey, adesso.ToString("s"), TimeSpan.FromSeconds(30));
// effettuo scrittura sul DB
await IocDbController.KeepAliveUpsertAsync(IdxMacchina, DateTime.Now, oraMacchina);
}
@@ -3906,7 +3921,7 @@ namespace MP.IOC.Data
{
// hard coded dimensione vettore DatiMacchine
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
// iniziualizzo con un valore... 0/0
// iniziualizzo con un valOut... 0/0
answ[0] = new KeyValuePair<string, string>("0", "0");
// ORA recupero da memoria redis...
try
@@ -3936,9 +3951,9 @@ namespace MP.IOC.Data
}
/// <summary>
/// restituisce il valore da REDIS associato al tag richeisto
/// restituisce il valOut da REDIS associato al tag richeisto
/// </summary>
/// <param name="redKey">Chiave in cui cercare il valore</param>
/// <param name="redKey">Chiave in cui cercare il valOut</param>
/// <returns></returns>
public string TagConfGetKey(string redKey)
{
@@ -4005,7 +4020,7 @@ namespace MP.IOC.Data
fluxLogList.Add(editFL);
}
// serializzo nuovamente valore
// serializzo nuovamente valOut
DossierFluxLogDTO? result = new DossierFluxLogDTO();
var ODLflux = result.ODL.ToList();
foreach (var item in fluxLogList)
@@ -4038,10 +4053,10 @@ namespace MP.IOC.Data
Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
// leggo i valori attuali...
List<ObjItemDTO> actValues = MachineParamList(idxMacchina);
// per ogni valore passatomi faccio insert o update rispetto elenco valori correnti in REDIS
// per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti in REDIS
foreach (var item in actValues)
{
// cerco nelle innovazioni SE CI SIA il valore...
// cerco nelle innovazioni SE CI SIA il valOut...
var trovato = innovations.Find(obj => obj.uid == item.uid);
// se non trovato nelle innovazioni...
if (trovato == null)
@@ -4074,11 +4089,23 @@ namespace MP.IOC.Data
/// <param name="idxMicroStato"></param>
/// <param name="valoreIn"></param>
/// <returns></returns>
public string ValoreSMI(int idxFamIn, int idxMicroStato, int valoreIn)
public async Task<string> ValoreSmiAsync(int idxFamIn, int idxMicroStato, int valoreIn)
{
string valOut = "";
var currHash = Utils.GetHashSMI(idxFamIn);
string field = $"{idxMicroStato}_{valoreIn}";
return RedisGetHashField(currHash, field);
var searchVal = await RedisGetHashFieldAsync(currHash, field);
if (!searchVal.HasValue)
{
// ricarico tabella (salvando in redis x ricerca successiva)!
var valori = await StateMachInByKeyAsync(idxFamIn);
if (valori.Any(x => x.Key == field))
{
searchVal = valori.FirstOrDefault(x => x.Key == field).Value;
}
}
valOut = $"{searchVal}";
return valOut;
}
/// <summary>
@@ -4378,7 +4405,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Helper standardizzazione valore dataora ricevuto da IOB remoti
/// Helper standardizzazione valOut dataora ricevuto da IOB remoti
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
@@ -4467,7 +4494,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce il valore booleano se la macchina sia di tipo MULTI (con più state machine x INGRESSI)
/// Restituisce il valOut booleano se la macchina sia di tipo MULTI (con più state machine x INGRESSI)
/// usando dati macchina in cache per evitare lookup ridondanti
/// </summary>
/// <param name="idxMacchina"></param>
@@ -4543,7 +4570,7 @@ namespace MP.IOC.Data
}
/// <summary>
/// Calcola l'effettivo valore da passare alla macchina a stati INGRESSI usando dati macchina in cache
/// Calcola l'effettivo valOut da passare alla macchina a stati INGRESSI usando dati macchina in cache
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="valore"></param>
@@ -4568,7 +4595,7 @@ namespace MP.IOC.Data
// non usato (x ora)
int.TryParse(datiMacc.ContainsKey("NumBit") ? datiMacc["NumBit"] : "0", out NumBit);
// recupero valore
// recupero valOut
valINT = int.Parse(valore, NumberStyles.HexNumber);
// filtro
newValInt = MP.Core.Utils.bMaskInt(valINT, BitFilt);
@@ -4626,7 +4653,8 @@ namespace MP.IOC.Data
double numSecCache = redisLongTimeCache;
// converto in formato dizionario...
if (dbResult != null)
{ // salvo 1:1 i valori... STATO
{
// salvo 1:1 i valori... STATO
result.Add("IdxMicroStato", $"{dbResult.IdxMicroStato}");
result.Add("IdxStato", $"{dbResult.IdxStato}");
result.Add("CodArticolo", $"{dbResult.CodArticolo}");
@@ -4653,9 +4681,14 @@ namespace MP.IOC.Data
result.Add("IdxFamMacc", $"{dbResult.IdxFamiglia}");
result.Add("simplePallet", $"{dbResult.SimplePallet}");
result.Add("palletChange", $"{dbResult.PalletChange}");
// durata cache in secondi dal valore insEnabled...
// durata cache in secondi dal valOut insEnabled...
//double numSecCache = ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache : redisLongTimeCache);
numSecCache = dbResult.InsEnabled ? redisShortTimeCache : redisLongTimeCache;
}
else
{
}
// dati master/slave
string isMaster = (await ListMasterAsync()).Contains(idxMacc) ? "1" : "0";
@@ -4708,8 +4741,8 @@ namespace MP.IOC.Data
i++;
}
// verifico il timeout (default 60 sec...)
var sTOutSmi = tryGetConfig("TmOut.SMI").Result;
int tOut = 60;
int tOut = 300;
var sTOutSmi = await tryGetConfigAsync("TmOut.SMI");
if (!string.IsNullOrEmpty(sTOutSmi))
{
int.TryParse(sTOutSmi, out tOut);
@@ -4773,6 +4806,35 @@ namespace MP.IOC.Data
return answ;
}
/// <summary>
/// Scrive una riga evento + una riga microstato insieme, ed effettua verifica necessità cambio stato
/// </summary>
/// <param name="newRecMsm">Record MicroStatoMacchina</param>
/// <param name="newRecEv">record EventList</param>
/// <returns></returns>
private async Task<inputComandoMapo> scriviRigaEventoAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
{
bool inserito = false;
try
{
// inserisco evento
inserito = await IocDbController.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
// faccio controllo per eventuale cambio stato da tab transizioni...
await CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRecEv.IdxMacchina, newRecEv.InizioStato ?? DateTime.Now, newRecEv.IdxTipo, newRecEv.CodArticolo, newRecEv.Value, newRecEv.MatrOpr, newRecEv.pallet);
}
catch (Exception exc)
{
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRecEv.IdxMacchina} | IdxTipo {newRecEv.IdxTipo} | codArticolo {newRecEv.CodArticolo} | Value {newRecEv.Value} | MatrOpr {newRecEv.MatrOpr} | Pallet {newRecEv.pallet} | dTime {newRecEv.InizioStato}{Environment.NewLine}{exc}");
}
// formatto output
inputComandoMapo answ = new inputComandoMapo();
answ.outValue = inserito.ToString();
answ.needStatusRefresh = true;
return answ;
}
/// <summary>
/// Scrive una riga di evento manuale (barcode) nel db + check cambio stato DiarioDiBordo
/// </summary>
@@ -4833,11 +4895,11 @@ namespace MP.IOC.Data
}
/// <summary>
/// Restituisce valore della stringa (SE disponibile)
/// Restituisce valOut della stringa (SE disponibile)
/// </summary>
/// <param name="keyName"></param>
/// <returns></returns>
private async Task<string> tryGetConfig(string keyName)
private async Task<string> tryGetConfigAsync(string keyName)
{
string answ = "";
// preselezione valori
@@ -4850,8 +4912,9 @@ namespace MP.IOC.Data
return answ;
}
#if false
/// <summary>
/// Restituisce il valore SPECIFICATO per la state machine ingressi
/// Restituisce il valOut SPECIFICATO per la state machine ingressi
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
/// </summary>
/// <param name="idxFamIn"></param>
@@ -4862,8 +4925,9 @@ namespace MP.IOC.Data
{
var currHash = Utils.GetHashSMI(idxFamIn);
string field = string.Format("{0}_{1}", idxMicroStato, valoreIn);
return RedisGetHashField(currHash, field);
}
return RedisGetHashFieldAsync(currHash, field);
}
#endif
/// <summary>
/// cerca codice in anagrafica macchine ed eventualmente inserisce nuova macchina