15 KiB
Piano Migrazione MpDataService → IIocService
Obiettivo: Standardizzare l'accesso dati su
IIocService(con FusionCache) e pensionareMpDataServicecome service layer principale diMP.IOC.Strategia: Ogni metodo
MpDataServiceusato dal controller viene migrato inIocService. La cache FusionCache avvolge le chiamate Redis/DB con le stesse durate e tag esistenti. I controller usano soloIIocService.
Architettura Target
IOBController
└── IIocService (scoped)
├── FusionCache (L1 Memory + L2 Redis + L3 DB via tags)
├── StackExchange.Redis (IDatabase) ← sorgente "live" per dati esterni
└── IIocRepository (scoped) ← DB access
Regola chiave: Redis diretto (scritto da IOB-WIN, altri programmi) resta accessibile via IDatabase _redisDb in IocService. FusionCache ha una durata equivalente per validare/invalidare coerentemente.
Stato Attuale
Minimal APIs — OK
I 3 endpoint in IobEndpoints.cs sono stati puliti e ora contengono solo:
GET api/IOB/api/IOB/alive— health checkGET api/IOB/enabled/{id}— usaawait iocService.IobInsEnabAsync(id)
I metodi setCounter e getCurrODL sono stati rimossi (troppo semplici, nel controller bastano).
Controller — Misto
| Usa DService | Usa IOCService |
|---|---|
| ~37 metodi | 5 metodi (getCounterTCRec, getCurrODL, setCounter, input, getTask2Exe in parte) |
MpDataService
- Registrato come singleton in
Program.cs:106 - Contiene ~80 metodi, molti con accesso Redis diretto senza FusionCache
IocServiceè scoped e usa già FusionCache
IocService
- Eredita da
MP.Data.Services.BaseServ(contieneGetOrFetchAsync<T>) - 12 metodi pubblici nell'interface
- Usa FusionCache per i metodi più critici (
IobInsEnabAsync,GetCurrOdlAsync,StatoProdMacchinaAsync)
Piano di Migrazione — Fasi
Fase 0: Preparazione (IocService base)
File: IIocService.cs, IocService.cs
0.1. IocService deve ereditare da MP.Data.Services.BaseServ (attuale IocService non lo fa) — per accedere a GetOrFetchAsync<T> condiviso
0.2. Aggiunta di IFusionCache _cache nel constructor (già presente in BaseServ)
0.3. Verifica: redisLongTimeCache e redisShortTimeCache usati da IocService per le durate FusionCache
Fase 1: Metodi KeepAlive + Task Management
Priorità: Alta — usati da quasi tutti gli altri metodi come precursori.
| MpDataService | → IocService | NOTE |
|---|---|---|
ScriviKeepAliveAsync |
✓ già duplicato in IocService |
Unificare, aggiungere FusionCache per la check key |
AddOptPar4Machine |
→ AddOptPar4Machine |
Redis hash, cache per tag machine |
AddTask4Machine |
→ AddTask4Machine |
Redis hash + backup, cache per tag machine |
mOptParMacchina |
→ GetOptParMacchina |
Redis hash read |
mTaskMacchina / mTaskMacchinaAsync |
→ GetTaskMacchina |
Redis hash read |
RemTask2ExeMacchinaAsync |
→ RemoveTask2ExeAsync |
Redis hash write + delete |
mSavedTaskMacchina |
→ GetSavedTasksMacchina |
Redis hash read |
AddCheckTask4Machine |
→ AddCheckTask4Machine |
Redis hash read/write |
AddTask4MacListAsync |
→ AddTaskListAsync |
Redis hash batch write |
Durata cache: redisShortTimeCache (2 min + jitter) per task hash (dati volatile)
Tag cache: Task:{idxMacchina}, OptPar:{idxMacchina}, SavedTask:{idxMacchina}
Fase 2: Metodi Process (INPUT, FLOG, ULOG)
Priorità: Altissima — il cuore del sistema, alto traffico.
| MpDataService | → IocService | NOTE |
|---|---|---|
ProcessInputAsync |
→ ProcessInputAsync |
GIÀ in IocService ✓ |
ProcessFluxLogAsync |
→ ProcessFluxLogAsync |
DB insert + Redis write |
ProcessUserLogAsync |
→ ProcessUserLogAsync |
DB insert multi-flux |
CheckMicroStatoAsync |
→ CheckMicroStatoAsync |
DB upsert + transizione |
scriviRigaEventoAsync |
→ WriteEventRecordAsync |
DB insert |
saveSigLogAsync |
→ SaveSignalLogAsync |
DB insert |
GetSrvDtEvent |
→ GetServerDateTime |
Pure logic — no cache |
ParseEventTime |
→ ParseEventTime |
GIÀ in IocService ✓ |
preProcInput |
→ PreProcessInput |
Pure logic — no cache |
ValidateInputParams / ValidateinputParams |
→ ValidateInputParams |
Pure logic — no cache |
Durata cache: Nessuna (scrittura). Tag invalidazione per MachineData:{idxMacchina} sui dati che influenzano.
Tag cache: Input:{idxMacchina}, FluxLog:{idxMacchina}, UserLog:{idxMacchina}, MicroStato:{idxMacchina}
Fase 3: Metodi ODL/PODL
Priorità: Alta — letture frequenti durante produzione.
| MpDataService | → IocService | NOTE |
|---|---|---|
GetCurrOdlAsync |
→ GetCurrOdlAsync |
GIÀ in IocService ✓ |
GetLastOdlAsync |
→ GetLastOdlAsync |
Usare GetOrFetchAsync<T> |
OdlCurrByMaccAsync |
→ GetCurrentOdlAsync |
Usare GetOrFetchAsync<T> |
AutoStartOdlAsync |
→ AutoStartOdlAsync |
Complesso — Redis + DB + eventi |
FixDailyDossierAsync |
→ FixDailyDossierAsync |
Chiamata batch |
OdlAutoDayGenAsync |
→ GenerateDailyOdlAsync |
DB stored procedure |
OdlAutoDayGenFullAsync |
→ GenerateDailyOdlFullAsync |
DB stored procedure |
POdlGetByKey |
→ GetPodlByKeyAsync |
Usare GetOrFetchAsync<T> |
POdlGetByMaccArtAsync |
→ GetPodlByMachineAsync |
Usare GetOrFetchAsync<T> |
Durata cache: redisLongTimeCache (5 min) per ODL/PODL
Tag cache: Odl:{idxMacchina}, Podl:{idxMacchina}
Fase 4: Metodi Contapezzi
Priorità: Alta — traffico continuo.
| MpDataService | → IocService | NOTE |
|---|---|---|
pzCounter |
→ GetPzCounterAsync |
Redis StringGet (lettura live) |
PzCounterTcAsync |
→ PzCounterTcAsync |
GIÀ in IocService ✓ |
saveCaricoPezzi |
→ SavePezziCaricoAsync |
Redis StringSet + DB insert |
SaveCounterAsync |
→ SaveCounterAsync |
GIÀ in IocService ✓ |
Durata cache: redisShortTimeCache per counter (dati volatile scritti da IOB esterni)
Tag cache: PzCounter:{idxMacchina}
Fase 5: Metodi Parametri Macchina
Priorità: Alta — metodo più chiamato (ogni richiesta legge i parametri).
| MpDataService | → IocService | NOTE |
|---|---|---|
MachineParamListAsync |
→ GetMachineParamsAsync |
CRITICO — Redis read, aggiungere FusionCache |
MachineParamListPendingWriteAsync |
→ GetPendingWriteParamsAsync |
Wrapper su GetMachineParamsAsync |
MachineParamListSetAsync |
→ SetMachineParamsAsync |
Redis StringSet |
MachineParamUpsertAsync |
→ UpsertMachineParamsAsync |
Redis read + write batch |
UpsertCurrObjItemsAsync |
→ UpsertMachineParamsAsync |
Duplicate — unificare con UpsertMachineParamsAsync |
Durata cache: redisShortTimeCache (2 min) per parametri macchina — dati scritti da IOB esterni ogni pochi secondi
Tag cache: MachineParams:{idxMacchina}
Fase 6: Metodi Anagrafica e Lookup
Priorità: Media — dati relativamente statici.
| MpDataService | → IocService | NOTE |
|---|---|---|
AnagStatiGetAllAsync |
→ GetAllStatiAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
ArticoliGetLastByMaccAsync |
→ GetLastArticlesByMachineAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
DossierLastByMachAsync |
→ GetLastDossiersByMachineAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
ListValuesFilt |
→ GetListValuesFilteredAsync |
Redis read (duplicare logica FusionCache) |
DecNumArtGetFiltAsync |
→ GetDecNumArticoliAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
MacchineGetFilt |
→ GetMachinesFilteredAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
Macchine2SlaveGetAllAsync |
→ GetMachineSlaveMapAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
MacchineRecipeArchive |
→ GetMachineRecipeArchivePathAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
ConfigGetAllAsync |
→ GetAllConfigAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
ConfFluxMach |
→ GetConfFluxByMachineAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
GetArtNumAsync |
→ GetArtNumByCodeAsync |
Interno — wrapper a DecNumArtGetFiltAsync |
MseGetAllAsync |
→ GetMachineStateExplAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
Durata cache: redisLongTimeCache (5 min + jitter)
Tag cache: AnagStati, Articoli:{idxMacchina}, Dossier:{idxMacchina}, Config, MSE, Macchine
Fase 7: Metodi Configurazione IOB + Redis Diretto
Priorità: Bassa — configurazione manuale, basso traffico.
| MpDataService | → IocService | NOTE |
|---|---|---|
SetIobMemMap |
→ SetIobMemMapAsync |
Redis StringSet |
SetIobConfYamlAsync |
→ SetIobConfYamlAsync |
Redis StringSet |
SaveMachineIobConf |
→ SaveMachineIobConfAsync |
Redis HashSet |
SaveMachine2Iob |
→ SaveMachine2IobAsync |
Redis StringSet |
SaveDataItemsAsync |
→ SaveDataItemsAsync |
Mongo o DB |
GetCurrObjItems |
→ GetMachineParamsAsync |
Duplicate — usare Fase 5 |
Fase 8: Metodi Logging e Monitoring
Priorità: Bassa — writing-only, nessun cache.
| MpDataService | → IocService | NOTE |
|---|---|---|
AlarmInsertAsync |
→ InsertAlarmLogAsync |
DB insert |
RemRebootLogAddAsync |
→ AddRebootLogAsync |
DB insert + Redis flush |
WriteEventRecordAsync (scriviRigaEventoAsync) |
→ WriteEventRecordAsync |
DB insert |
FluxLogSaveSnapshotAsync |
→ SaveFluxSnapshotAsync |
DB stored procedure |
DossierLastByMachResetAsync |
→ ResetDossierCacheAsync |
Redis delete |
FluxLogFirstByMachAsync |
→ GetFirstFluxLogsAsync |
GIÀ usa GetOrFetchAsync<T> in MpDataService |
Fase 9: Metodi Helper e Internal
Priorità: Bassa — usati internamente.
| MpDataService | → IocService | NOTE |
|---|---|---|
mDatiMacchineAsync |
→ GetMachineDataAsync |
Redis HashGetAll + reset |
ResetDatiMacchinaAsync |
→ ResetMachineDataAsync |
Redis transaction batch |
StateMachInByKeyAsync |
→ GetStateMachineIngressiAsync |
Redis Hash |
resetMSMIAsync |
→ ResetMultiSMIAsync |
Redis Hash write |
resetSMIAsync |
→ ResetSMIAsync |
Redis Hash write |
ValoreSmiAsync |
→ GetSMIValueAsync |
Redis HashField get |
isMulti |
→ IsMultiMachine |
Pure logic |
ListMasterAsync / ListSlaveAsync |
→ GetMasterListAsync / GetSlaveListAsync |
Redis cache |
getRandTOut |
→ GetRandomTimeout |
Shared in BaseServ |
RedisCountKey, RedisDelKey, RedisFlushPatternAsync |
→ FlushKeysByPatternAsync |
Admin only |
RedisGetHashDictAsync, RedisSetHashDictAsync |
→ RedisGet/HashDictAsync |
Wrapper utilities |
Fase 10: Pulizia Controller
10.1. Sostituire DService con IOCService in IOBController
Cambiare constructor e tutte le chiamate:
// PRIMA
public IOBController(IConfiguration configuration, MpDataService DataService, IIocService IService)
{
DService = DataService;
IOCService = IService;
}
// DOPO
public IOBController(IIocService service)
{
_service = service;
}
Poi sostituire ogni DService.Xxx(...) con _service.Xxx(...).
10.2. Rimuovere MpDataService dal controller
- Rimuovere la property
DService - Rimuovere il parametro dal constructor
- Unificare le chiamate miste (alcuni metodi fanno
DService.ScriviKeepAliveAsync+IOCService.Xxx)
10.3. Spostare i private method in IocService
I metodi processEvListJsonAsync, processFLogJsonAsync, processULogJsonAsync contengono logica di business:
processEvListJsonAsync→ProcessEventListJsonAsyncinIocServiceprocessFLogJsonAsync→ProcessFluxLogJsonAsyncinIocService(complesso — usaMachineParamListAsync+UpsertCurrObjItemsAsync)processULogJsonAsync→ProcessUserLogJsonAsyncinIocService
10.4. Rimuovere MpDataService da Program.cs
// RIMUOVERE:
// builder.Services.AddSingleton<MpDataService>();
Riepilogo Metodi da Migrire
| Categoria | Metodi da aggiungere a IocService |
|---|---|
| KeepAlive + Task | ~9 metodi |
| Process (INPUT/FLOG/ULOG) | ~9 metodi |
| ODL/PODL | ~8 metodi |
| Contapezzi | ~3 metodi |
| Parametri Macchina | ~4 metodi |
| Anagrafica/Lookup | ~11 metodi |
| Config IOB | ~5 metodi |
| Logging | ~6 metodi |
| Helper/Internal | ~10 metodi |
| TOTALE | ~65 metodi |
Di questi, ~15 sono già in IocService o BaseServ. Quindi ~50 nuovi metodi da implementare.
Criteri di Validazione
- Build —
./build_all_par.ps1 --agentsenza errori - Functional parity — ogni endpoint del controller restituisce lo stesso output di prima
- Cache behavior — i metodi migrati registrano
data.sourcecome TRACE/DEBUG - No
MpDataServicereferences nel controller Program.cs—MpDataServicerimosso dalla DI registration
Sequenza di Sviluppo Consigliata
Fase 1 → Fase 4: Blocchi "hot" (keepalive, task, counter)
Fase 5: Parametri macchina (blocco più critico per perf)
Fase 2: Process (INPUT/FLOG/ULOG - cuore dell'app)
Fase 3: ODL/PODL
Fase 6: Anagrafica (dati statici, meno rischioso)
Fase 7-9: Config + Logging + Helper
Fase 10: Cleanup finale
Ogni fase va build-ata e testata prima di procedere alla successiva.
Note Tecniche
Caching su Redis diretto
Per i dati scritti da programmi esterni (IOB-WIN, ecc.), il pattern è:
1. Lettura: _redisDb.StringGet/HashGet (dati "live")
2. Scrittura: programmi esterni scrivono in Redis direttamente
3. FusionCache: durata pari a redisShortTimeCache o redisLongTimeCache
- Il backplane Redis invalida L1 negli altri worker
- Se un programma esterno scrive, la prossima lettura dal controller fa cache-miss
Questo è coerente con l'architettura attuale: il controller legge Redis (sorgente di verità) e FusionCache avvolge per ridurre i round-trip.
Tagging Strategy
MachineData:{idxMacchina} — dati macchina generali (ResetDatiMacchina)
MachineParams:{idxMacchina} — parametri macchina (MachineParamListAsync)
Task:{idxMacchina} — task da eseguire
PzCounter:{idxMacchina} — contapezzi
Odl:{idxMacchina} — ODL correnti
Podl:{idxMacchina} — PODL
Input:{idxMacchina} — log input
FluxLog:{idxMacchina} — log flux
UserLog:{idxMacchina} — log user
Transizioni di Scope
MpDataService è singleton → IIocService è scoped. Questo va bene per le minimal APIs (che iniettano IIocService correttamente). Per il controller, dopo la rimozione di MpDataService, il controller diventerà scoped di default (già lo è per [ApiController]).
IocService constructor
Attuale (da MP.Data.Services.IOC.IocService):
public IocService(IConfiguration config, IConnectionMultiplexer redis,
IFusionCache cache, IIocRepository repo,
IServiceScopeFactory scopeFactory)
Da MP.Data.Services.BaseServ:
public BaseServ(IConfiguration configuration, IFusionCache cache, IConnectionMultiplexer redConn)
La gerarchia sarà: IocService estende BaseServ e il constructor chiama base(configuration, cache, redConn).