fix(worker): review follow-up — ghost cache entries, ReadBulk dedupe/pumping, fault hygiene
ci / nightly-windev (push) Has been skipped
ci / java (push) Successful in 2m15s
ci / portable (push) Failing after 4m19s
ci / windows-x86 (push) Successful in 6m16s

- AddItem/AddItem2/AddBufferedItem drop stale cache entries for a reused handle id
- ReadBulk: dedupe handles within a batch (advise/teardown once, fan out result);
  pump every 16 items in add/advise and teardown phases
- alarm poll stops without recording a fault once StaRuntime.LoopFault is set
- StaRuntime skips the loop-fault handler during a requested shutdown
- StaHung loop fault diagnostic carries type + HRESULT only
- gateway.md documents ReadBulk's shared deadline
This commit is contained in:
Joseph Doherty
2026-10-22 08:23:05 -04:00
parent 4ea3672b1e
commit 38fbbde191
9 changed files with 375 additions and 21 deletions
+9 -2
View File
@@ -569,8 +569,15 @@ returns one result per requested entry — per-entry failures populate
advised (`was_cached = true`, no subscription side-effects), or by
taking a full `AddItem` + `Advise` + wait-for-first-OnDataChange +
`UnAdvise` + `RemoveItem` snapshot lifecycle when no live subscription
exists (`was_cached = false`). Per-tag timeouts surface as
`was_successful = false` rather than throwing. The cache lives on the
exists (`was_cached = false`). `timeout_ms` is one shared deadline for
the whole command, not a per-tag budget: the worker adds and advises
every uncached tag first, waits once for all of them, then tears them
all down, so the STA is held for at most one `timeout_ms` (plus the
add/advise and teardown COM calls, during which it pumps every 16 tags).
Each tag that has not delivered by the deadline surfaces its own
`was_successful = false` timeout rather than throwing. Duplicate
addresses that MXAccess resolves to the same item handle share one
subscription and receive the same result. The cache lives on the
worker's `MxAccessValueCache`, populated by `MxAccessBaseEventSink` on
every `OnDataChange` after the event clears the outbound queue.
Required scope: `invoke:read`. `timeout_ms == 0` uses the worker's