diff --git a/MP.Data/Services/IOC/IocService.cs b/MP.Data/Services/IOC/IocService.cs
index 5db8d93a..8669e3e1 100644
--- a/MP.Data/Services/IOC/IocService.cs
+++ b/MP.Data/Services/IOC/IocService.cs
@@ -152,7 +152,6 @@ namespace MP.Data.Services.IOC
// 3. Conversione efficiente da RedisValue a string (evita l'interpolazione $"{val}")
string? sRedisVal = val;
return IsStringTrue(sRedisVal);
-
#if false
var rKey = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
var val = await _redisDb.HashGetAsync(rKey, "insEnabled");
@@ -170,7 +169,8 @@ namespace MP.Data.Services.IOC
return !string.IsNullOrEmpty(sVal) && (sVal == "1" || sVal.ToLower() == "true");
#endif
},
- expiration: GetRandTOut(30),
+ expiration: GetRandTOut(60),
+ //expiration: GetRandTOut(30),
tagList: ["IOC_IobInsEnab", cKey, idxMacchina]
);
}
diff --git a/MP.Data/Services/Utils/IStatsDetailService.cs b/MP.Data/Services/Utils/IStatsDetailService.cs
index 751f003b..6f84b5af 100644
--- a/MP.Data/Services/Utils/IStatsDetailService.cs
+++ b/MP.Data/Services/Utils/IStatsDetailService.cs
@@ -63,6 +63,13 @@ namespace MP.Data.Services.Utils
///
Task ResetCache();
+ ///
+ /// Forza il reset della cache REDIS x il pattern richiesto
+ ///
+ ///
+ ///
+ Task ResetCache(string pattern);
+
///
/// Inserisce o aggiorna in batch le statistiche di dettaglio nel database.
/// Opzionalmente elimina i record precedenti nel periodo specificato.
diff --git a/MP.Data/Services/Utils/StatsDetailService.cs b/MP.Data/Services/Utils/StatsDetailService.cs
index b637b33d..3c10ad2b 100644
--- a/MP.Data/Services/Utils/StatsDetailService.cs
+++ b/MP.Data/Services/Utils/StatsDetailService.cs
@@ -22,7 +22,7 @@ namespace MP.Data.Services.Utils
IConnectionMultiplexer redis,
IFusionCache cache,
IStatsDetailRepository repo
- ) : base(config,cache, redis)
+ ) : base(config, cache, redis)
{
_className = "StatsDetail";
_repo = repo;
@@ -134,6 +134,14 @@ namespace MP.Data.Services.Utils
await ClearCacheAsync($"{_redisBaseKey}:*");
}
+ ///
+ public async Task ResetCache(string pattern)
+ {
+ // tolgo eventuali ":" finali
+ pattern = pattern.EndsWith(":") ? pattern.Substring(0, pattern.Length - 1) : pattern;
+ await ClearCacheAsync($"{pattern}:*");
+ }
+
///
public async Task UpsertManyAsync(List listRecords, bool removeOld)
{
diff --git a/MP.IOC/Components/Pages/CallStats.razor.cs b/MP.IOC/Components/Pages/CallStats.razor.cs
index 427f7037..c8cfbc54 100644
--- a/MP.IOC/Components/Pages/CallStats.razor.cs
+++ b/MP.IOC/Components/Pages/CallStats.razor.cs
@@ -14,6 +14,7 @@ namespace MP.IOC.Components.Pages
protected override async Task OnInitializedAsync()
{
+ MpIoNS = Config.GetValue("ServerConf:MpIoNS") ?? "MP";
await ReloadData();
}
@@ -105,6 +106,9 @@ namespace MP.IOC.Components.Pages
[Inject]
private IIocService IocService { get; set; } = null!;
+ [Inject]
+ private IConfiguration Config { get; set; } = null!;
+
#endregion Private Properties
#region Private Methods
@@ -114,8 +118,14 @@ namespace MP.IOC.Components.Pages
return currStatSel != null && currStatSel.Title == curKey ? "active" : "";
}
+ private string MpIoNS = "";
+
private async Task DoForceReload()
{
+ // svuoto cache dati IoNS...
+ var dtMaccKey = Utils.RedKeyDatiMacc("", MpIoNS);
+ await SDetService.ResetCache(dtMaccKey);
+ // resto delle cache
await SDetService.ResetCache();
await IocService.ClearFusionCache();
DoReset();
diff --git a/MP.IOC/MP.IOC.csproj b/MP.IOC/MP.IOC.csproj
index 25647da6..202183d5 100644
--- a/MP.IOC/MP.IOC.csproj
+++ b/MP.IOC/MP.IOC.csproj
@@ -4,7 +4,7 @@
net8.0
enable
enable
- 8.16.2606.1312
+ 8.16.2606.1511
diff --git a/MP.IOC/Resources/ChangeLog.html b/MP.IOC/Resources/ChangeLog.html
index 7ed31778..8bf6f1c5 100644
--- a/MP.IOC/Resources/ChangeLog.html
+++ b/MP.IOC/Resources/ChangeLog.html
@@ -1,6 +1,6 @@
Modulo MP-IOC
- Versione: 8.16.2606.1312
+ Versione: 8.16.2606.1511
Note di rilascio:
-
diff --git a/MP.IOC/Resources/VersNum.txt b/MP.IOC/Resources/VersNum.txt
index 84233792..27bab3be 100644
--- a/MP.IOC/Resources/VersNum.txt
+++ b/MP.IOC/Resources/VersNum.txt
@@ -1 +1 @@
-8.16.2606.1312
+8.16.2606.1511
diff --git a/MP.IOC/Resources/manifest.xml b/MP.IOC/Resources/manifest.xml
index 6c9ebef2..f9e64e4d 100644
--- a/MP.IOC/Resources/manifest.xml
+++ b/MP.IOC/Resources/manifest.xml
@@ -1,6 +1,6 @@
-
- 8.16.2606.1312
+ 8.16.2606.1511
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/refactor_migration.md b/MP.IOC/refactor_migration.md
new file mode 100644
index 00000000..ab91040a
--- /dev/null
+++ b/MP.IOC/refactor_migration.md
@@ -0,0 +1,377 @@
+# Piano Migrazione MpDataService → IIocService
+
+> **Obiettivo**: Standardizzare l'accesso dati su `IIocService` (con FusionCache) e pensionare `MpDataService` come service layer principale di `MP.IOC`.
+>
+> **Strategia**: Ogni metodo `MpDataService` usato dal controller viene migrato in `IocService`. La cache FusionCache avvolge le chiamate Redis/DB con le stesse durate e tag esistenti. I controller usano solo `IIocService`.
+
+---
+
+## 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 check
+- `GET api/IOB/enabled/{id}` — usa `await 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` (contiene `GetOrFetchAsync`)
+- 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` 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` |
+| `OdlCurrByMaccAsync` | → `GetCurrentOdlAsync` | Usare `GetOrFetchAsync` |
+| `AutoStartOdlAsync` | → `AutoStartOdlAsync` | Complesso — Redis + DB + eventi |
+| `FixDailyDossierAsync` | → `FixDailyDossierAsync` | Chiamata batch |
+| `OdlAutoDayGenAsync` | → `GenerateDailyOdlAsync` | DB stored procedure |
+| `OdlAutoDayGenFullAsync` | → `GenerateDailyOdlFullAsync` | DB stored procedure |
+| `POdlGetByKey` | → `GetPodlByKeyAsync` | Usare `GetOrFetchAsync` |
+| `POdlGetByMaccArtAsync` | → `GetPodlByMachineAsync` | Usare `GetOrFetchAsync` |
+
+**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` in MpDataService |
+| `ArticoliGetLastByMaccAsync` | → `GetLastArticlesByMachineAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `DossierLastByMachAsync` | → `GetLastDossiersByMachineAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `ListValuesFilt` | → `GetListValuesFilteredAsync` | Redis read (duplicare logica FusionCache) |
+| `DecNumArtGetFiltAsync` | → `GetDecNumArticoliAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `MacchineGetFilt` | → `GetMachinesFilteredAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `Macchine2SlaveGetAllAsync` | → `GetMachineSlaveMapAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `MacchineRecipeArchive` | → `GetMachineRecipeArchivePathAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `ConfigGetAllAsync` | → `GetAllConfigAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `ConfFluxMach` | → `GetConfFluxByMachineAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService |
+| `GetArtNumAsync` | → `GetArtNumByCodeAsync` | Interno — wrapper a DecNumArtGetFiltAsync |
+| `MseGetAllAsync` | → `GetMachineStateExplAsync` | GIÀ usa `GetOrFetchAsync` 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` 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:
+
+```csharp
+// 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` → `ProcessEventListJsonAsync` in `IocService`
+- `processFLogJsonAsync` → `ProcessFluxLogJsonAsync` in `IocService` (complesso — usa `MachineParamListAsync` + `UpsertCurrObjItemsAsync`)
+- `processULogJsonAsync` → `ProcessUserLogJsonAsync` in `IocService`
+
+### 10.4. Rimuovere `MpDataService` da `Program.cs`
+
+```csharp
+// RIMUOVERE:
+// builder.Services.AddSingleton();
+```
+
+---
+
+## 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
+
+1. **Build** — `./build_all_par.ps1 --agent` senza errori
+2. **Functional parity** — ogni endpoint del controller restituisce lo stesso output di prima
+3. **Cache behavior** — i metodi migrati registrano `data.source` come TRACE/DEBUG
+4. **No `MpDataService` references** nel controller
+5. **`Program.cs`** — `MpDataService` rimosso 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`):
+```csharp
+public IocService(IConfiguration config, IConnectionMultiplexer redis,
+ IFusionCache cache, IIocRepository repo,
+ IServiceScopeFactory scopeFactory)
+```
+
+Da `MP.Data.Services.BaseServ`:
+```csharp
+public BaseServ(IConfiguration configuration, IFusionCache cache, IConnectionMultiplexer redConn)
+```
+
+La gerarchia sarà: `IocService` estende `BaseServ` e il constructor chiama `base(configuration, cache, redConn)`.