Record the managed GUID alarm-ack live result
The 2026-10-18 live test on the dev rig showed the opt-in managed ack path cannot work as built: AlarmClient.RegisterConsumer returns -65 alongside the worker's wnwrap reader (the worker then silently falls back to wnwrap), the managed client does not recognise the wnwrap GUID even standalone, and the gateway's GUID arm sends empty identity fields. Replace the docs' claim that the path works with the measured results and tell operators to leave MXGATEWAY_USE_MANAGED_ALARM_ACK unset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -793,27 +793,54 @@ in the codebase for the forward-compat shape, but the gateway-side
|
|||||||
`AcknowledgeAlarmByName` when the public RPC supplies a recognizable
|
`AcknowledgeAlarmByName` when the public RPC supplies a recognizable
|
||||||
`Provider!Group.Tag` reference.
|
`Provider!Group.Tag` reference.
|
||||||
|
|
||||||
**Opt-in managed GUID ack.** Setting `MXGATEWAY_USE_MANAGED_ALARM_ACK=1`
|
**Opt-in managed GUID ack — does not work on this rig (live-tested
|
||||||
in the gateway's environment (workers inherit it) routes GUID-keyed acks
|
2026-10-18).** Setting `MXGATEWAY_USE_MANAGED_ALARM_ACK=1` in the
|
||||||
through `aaAlarmManagedClient.AlarmClient.AlarmAckByGUID` instead of the
|
gateway's environment (workers inherit it) makes the worker build an
|
||||||
wnwrap method. That managed method is implemented on this build and
|
`AaManagedAlarmAckConsumer`, which drives
|
||||||
carries operator domain and full name natively. The worker reaches it by
|
`aaAlarmManagedClient.AlarmClient` by reflection (its members are
|
||||||
reflection (`AaManagedAlarmAckConsumer`) because the members are
|
non-public) and is meant to take GUID-keyed acks in place of the
|
||||||
non-public, and runs its own Initialize → Register → Subscribe lifecycle
|
wnwrap method. The live test shows it cannot do that as built, so leave
|
||||||
against the alarm subscription expression. The path is deliberately
|
the flag off.
|
||||||
conservative:
|
|
||||||
|
|
||||||
- If the DLL cannot load or the lifecycle returns a non-zero status, the
|
The test raised `TestMachine_001.TestAlarm001` with a secured write,
|
||||||
worker drops back to the wnwrap ack path; alarm reads never fail
|
read its GUID from the wnwrap XML snapshot (the public API exposes no
|
||||||
because of it.
|
alarm GUIDs), and acknowledged it through the `AcknowledgeAlarm` RPC
|
||||||
- Subtag-mode acks (forced subtag, or failover currently on the standby)
|
with the flag on:
|
||||||
stay on the subtag consumer: their GUIDs are synthetic and only it can
|
|
||||||
resolve them.
|
|
||||||
- By-name acks stay on wnwrap — `AlarmClient` has no by-name ack.
|
|
||||||
|
|
||||||
A zero return still means *accepted*, not *applied*; a secured
|
| Step | Result |
|
||||||
(`MxSecurityOperate`) alarm needs an authenticated operator. The skip-gated
|
|---|---|
|
||||||
`AlarmManagedGuidAckLiveSmokeTests` asserts the ack actually lands.
|
| RPC ack by GUID, flag off (control) | `NotImplementedException`; `.Acked` stays `False` |
|
||||||
|
| RPC ack by GUID, flag on | Same `NotImplementedException`; `.Acked` `False`, `.AckMsg` empty |
|
||||||
|
| `AlarmClient.RegisterConsumer` in a process with a registered wnwrap consumer | `-65` — and wnwrap gets `-65` if the managed client registered first; a real `hWnd` does not help |
|
||||||
|
| Managed client alone in its own process, records loaded | `AlarmAckByGUID` → `-1`, `SelectByGUID` → `-1` for the wnwrap GUID in both byte orders, `AlarmAckSelected` → `-57` |
|
||||||
|
|
||||||
|
Three separate problems follow:
|
||||||
|
|
||||||
|
1. **The two libraries cannot share a process.** The worker always runs
|
||||||
|
a wnwrap reader, so the managed `RegisterConsumer` fails with `-65`.
|
||||||
|
The dispatcher is built to drop back to the wnwrap ack path on a
|
||||||
|
lifecycle failure (so alarm reads keep working), and it does so
|
||||||
|
silently — which is why the flag-on RPC is indistinguishable from the
|
||||||
|
control.
|
||||||
|
2. **The managed client does not recognise the wnwrap GUID.** `-1` from
|
||||||
|
`SelectByGUID` is "not found", not a security refusal, even with the
|
||||||
|
client holding records. Getting the client's own identifier for the
|
||||||
|
alarm is not reliable either: `GetHighPriAlarm` mostly throws the
|
||||||
|
FILETIME `ArgumentOutOfRangeException` described above. The
|
||||||
|
`MxSecurityOperate` question was therefore never reached.
|
||||||
|
3. **The gateway does not send the identity fields.** Its GUID arm fills
|
||||||
|
`OperatorNode`, `OperatorDomain` and `OperatorFullName` with empty
|
||||||
|
strings, so the domain and full name the managed method carries
|
||||||
|
would not arrive through the public RPC even if 1 and 2 were solved.
|
||||||
|
|
||||||
|
A working managed ack would need the client hosted out of process, a way
|
||||||
|
to resolve the alarm to the identifier the managed client uses, and the
|
||||||
|
identity fields plumbed through the gateway. Routing rules the worker
|
||||||
|
already applies stay correct and would carry over: subtag-mode acks
|
||||||
|
(synthetic GUIDs) stay on the subtag consumer, and by-name acks stay on
|
||||||
|
wnwrap because `AlarmClient` has no by-name ack. The skip-gated
|
||||||
|
`AlarmManagedGuidAckLiveSmokeTests` exercises the in-process
|
||||||
|
arrangement and hits problem 1.
|
||||||
|
|
||||||
### 5. STA / threading — resolved
|
### 5. STA / threading — resolved
|
||||||
|
|
||||||
|
|||||||
@@ -446,11 +446,12 @@ behavior.
|
|||||||
The alarm monitor is independent of client sessions: `AcknowledgeAlarm` and
|
The alarm monitor is independent of client sessions: `AcknowledgeAlarm` and
|
||||||
`StreamAlarms` are session-less RPCs served by the monitor.
|
`StreamAlarms` are session-less RPCs served by the monitor.
|
||||||
|
|
||||||
GUID-keyed acknowledges can opt into AVEVA's managed alarm client by setting
|
The worker also reads `MXGATEWAY_USE_MANAGED_ALARM_ACK` (inherited from the
|
||||||
the environment variable `MXGATEWAY_USE_MANAGED_ALARM_ACK=1` on the gateway
|
gateway process). Setting it to `1` is meant to route GUID-keyed acknowledges
|
||||||
process (workers inherit it; under NSSM, add it to the service environment).
|
through AVEVA's managed alarm client, but a live test (2026-10-18) showed the
|
||||||
It is off by default and has no `MxGateway:*` option because it is still
|
path cannot work as built: the managed client fails to register alongside the
|
||||||
awaiting live confirmation on the rig. See
|
worker's wnwrap reader and the worker silently falls back to wnwrap. Leave it
|
||||||
|
unset. It has no `MxGateway:*` option. See
|
||||||
[AlarmClientDiscovery](./AlarmClientDiscovery.md) ("Opt-in managed GUID ack").
|
[AlarmClientDiscovery](./AlarmClientDiscovery.md) ("Opt-in managed GUID ack").
|
||||||
|
|
||||||
### Alarm fallback options
|
### Alarm fallback options
|
||||||
|
|||||||
Reference in New Issue
Block a user