docs: write-completion correlation configuration and semantics
This commit is contained in:
@@ -534,6 +534,48 @@ against the live MXAccess attribute set.
|
||||
- [Alarm Client Discovery — Subtag provider](./AlarmClientDiscovery.md)
|
||||
- [gRPC Contract — provider_status and degraded fields](./Grpc.md)
|
||||
|
||||
## Secured-Write Completion Correlation
|
||||
|
||||
MXAccess writes are fire-and-forget: the toolkit call returns before the
|
||||
Galaxy commit, and the per-item outcome only exists in the later
|
||||
`OnWriteComplete` COM callback. The original unary write reply therefore
|
||||
proved worker-side command acceptance only, forcing consumers (OtOpcUa's
|
||||
GalaxyDriver) to report every write as provisionally good.
|
||||
|
||||
For `WriteSecured`/`WriteSecured2` the worker now holds the unary reply for a
|
||||
bounded window (`MxGateway:Worker:WriteCompletionWaitMilliseconds`, default
|
||||
1.5 s, `0` disables; conveyed to the worker via
|
||||
`MXGATEWAY_WORKER_WRITE_COMPLETION_WAIT_MS`) and copies the matching
|
||||
callback's status rows onto `MxCommandReply.statuses`. Key choices, argued in
|
||||
[the design doc](./plans/2026-08-09-write-completion-correlation-design.md):
|
||||
|
||||
- **Pump-wait on the STA, not a parked reply.** The executor holds the STA
|
||||
thread but pumps Windows messages each poll — the shipped ReadBulk pattern —
|
||||
because commands serialize per session anyway, so freeing the STA during the
|
||||
wait buys nothing and a parked reply would change the dispatcher/pipe
|
||||
contracts.
|
||||
- **Version baseline before the COM call** closes the fast-completion edge: a
|
||||
callback that dispatches while `WriteSecured` is still on the stack still
|
||||
correlates.
|
||||
- **Timeout returns today's shape** (protocol OK, empty statuses):
|
||||
unconfirmed is honest; a synthesized failure row would trigger consumer-side
|
||||
write-revert logic on slow-but-successful commits. The 1.5 s default stays
|
||||
inside OtOpcUa's 2 s Tier A write-resilience budget.
|
||||
- **Parity preserved.** `protocol_status`/`hresult` keep describing
|
||||
acceptance; the MXAccess outcome (success or failure) rides only in
|
||||
`statuses[0]`; the `OnWriteComplete` event still streams unchanged (nothing
|
||||
swallowed, nothing synthesized).
|
||||
- **Scope: secured writes only.** Plain `Write`/`Write2` and bulk writes stay
|
||||
fire-and-forget — the wait would add a device round-trip per write to
|
||||
high-rate supervisory loops.
|
||||
- **Best-effort correlation.** The callback carries only
|
||||
`(hItem, statuses)` — no transaction id — so concurrent writes to the same
|
||||
item within the window can swap rows; benign for the serialized single-write
|
||||
consumer contract.
|
||||
- **Client cancellation needs no special path**: a caller abandoning the RPC
|
||||
mid-wait leaves the worker to finish its bounded wait and reply; the gateway
|
||||
discards the reply, the session is never faulted.
|
||||
|
||||
## Later Revisit Items
|
||||
|
||||
These are explicit post-v1 revisit items, not open blockers:
|
||||
|
||||
@@ -114,6 +114,7 @@ launch CWD (SEC-01, SEC-33).
|
||||
| `MxGateway:Worker:StartupProbeRetryAttempts` | `3` | Number of retry attempts for transient worker startup probe failures before pipe connection and handshake continue. |
|
||||
| `MxGateway:Worker:StartupProbeRetryDelayMilliseconds` | `250` | Delay between transient startup probe retry attempts. |
|
||||
| `MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds` | `2000` | Per-attempt timeout used by the worker named-pipe connect retry path. The overall pipe connection still stays under the startup budget. |
|
||||
| `MxGateway:Worker:WriteCompletionWaitMilliseconds` | `1500` | Bounded wait the worker holds a `WriteSecured`/`WriteSecured2` reply for the matching MXAccess `OnWriteComplete` callback, so the reply's `statuses` carry the real commit outcome. `0` disables the wait (pure fire-and-forget replies). Must be `>= 0`. The gateway conveys the value to the worker via the `MXGATEWAY_WORKER_WRITE_COMPLETION_WAIT_MS` environment variable. Consumers that time their own writes must budget above this wait: OtOpcUa's GalaxyDriver wraps gateway writes in a 2 s Tier A resilience timeout, so a deployment raising this option past ~2000 must raise that driver `ResilienceConfig` write timeout in step or slow-but-successful commits surface as consumer-side failures. |
|
||||
| `MxGateway:Worker:ShutdownTimeoutSeconds` | `10` | Grace period for worker shutdown before the gateway treats shutdown as failed and may kill the worker process tree. |
|
||||
| `MxGateway:Worker:HeartbeatIntervalSeconds` | `5` | Worker heartbeat send interval and gateway heartbeat check cadence input. |
|
||||
| `MxGateway:Worker:HeartbeatGraceSeconds` | `15` | Maximum age of the last worker heartbeat before the gateway faults the worker. This must be greater than or equal to `HeartbeatIntervalSeconds`. |
|
||||
|
||||
Reference in New Issue
Block a user