diff --git a/scripts/install/Refresh-Services.ps1 b/scripts/install/Refresh-Services.ps1 index bd81e10b..40c441e4 100644 --- a/scripts/install/Refresh-Services.ps1 +++ b/scripts/install/Refresh-Services.ps1 @@ -118,6 +118,43 @@ Run { -c Release -o (Join-Path $PublishRoot "lmxopcua\WonderwareHistorian") | Out-Null } "dotnet publish (Host + sidecar)" +# ------------------------------------------------------------------------ +# Step 4b: Assert the Wonderware historian sidecar deploy is COMPLETE +# ------------------------------------------------------------------------ +# A partial/stale sidecar deploy (e.g. a hand-copy that bypassed the +# `dotnet publish` above) silently drops the net48 binding-redirect +# .exe.config and the transitive runtime DLLs MessagePack needs — most +# notably System.Memory.dll. The sidecar then JIT-load-faults inside +# PipeServer.RunOneConnectionAsync ("FileNotFoundException: System.Memory, +# Version=4.0.1.2") and NSSM crash-loops it (exit 2 every ~2 min, ~120 s of +# retry backoff before it gives up). Fail loudly here so an incomplete deploy +# is caught at publish time instead of by a production crash-loop. +# (Root-caused 2026-06-12; these four files have no alternate resolution path, +# unlike the AVEVA SDK DLLs which the Historian install can also supply.) + +if (-not $WhatIf) { + Step "Verifying Wonderware historian sidecar deploy is complete" + + $sidecarDir = Join-Path $PublishRoot "lmxopcua\WonderwareHistorian" + $sidecarRequired = @( + 'OtOpcUa.Driver.Historian.Wonderware.exe', + 'OtOpcUa.Driver.Historian.Wonderware.exe.config', # net48 binding redirects + 'System.Memory.dll', # MessagePack's load-bearing dep + 'MessagePack.dll' + ) + + $missing = $sidecarRequired | Where-Object { -not (Test-Path (Join-Path $sidecarDir $_)) } + + if ($missing.Count -gt 0) { + $msg = "Wonderware historian sidecar deploy at '$sidecarDir' is INCOMPLETE — missing: " + + "$($missing -join ', '). It would crash-loop with a FileNotFoundException in PipeServer. " + + "Re-run the sidecar 'dotnet publish' into that folder (Step 4) — never hand-copy a partial build output." + throw $msg + } + + Write-Host " sidecar deploy OK — all $($sidecarRequired.Count) load-bearing files present" -ForegroundColor DarkGreen +} + # ------------------------------------------------------------------------ # Step 5: Service env block — ensure OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED # is set on the Wonderware historian service (PR C.2 toggle).