fix(mtconnect): read-path restart publishes the new cursor; document the review trade-offs (review m6, m1, m4, m5, m8)
- m6: a /current read that sees a new Agent instanceId now also publishes the new process's cursor (generation-checked, captured with the read's session), so a later subscription does not open at the dead instance's sequence and flicker through a clear + re-baseline. Pinned in the T-2 test. - Documented (code + docs/drivers/MTConnect.md): m1 the bounded stale-read window of a stream stalled without failing; m4 a refused multi-pair PUT's retry may re-send an already-applied pair (harmless); m5 a non-Agent 200 now reads reachable to the ping; m8 a refused raised count takes one transient blip before the step-back. - m10 confirmed: no host key is persisted (DriverHostStatus dropped, #521) - the redacted HostName only changes an in-memory /hosts key for a query-bearing URI. Refs #743 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -90,7 +90,7 @@ request/response handshake — is a different mechanism and remains deferred; se
|
||||
| `IReadable` | `ReadAsync` → the live `/sample` pump's index while it is delivering and healthy, else one `/current` per call | **Not the production data path** — see below |
|
||||
| `IWritable` | `WriteAsync` → `POST {agent}/{device}?{dataItemId}={value}` on the Agent's `AllowPut` surface | **Off by default** — needs `Write.Enabled` **and** the Agent's `AllowPut`; CONDITION items are refused |
|
||||
| `ISubscribable` | `SubscribeAsync`/`OnDataChange` — the shared `/sample` long-poll pump | **The production data path** |
|
||||
| `IHostConnectivityProbe` | periodic headers-only `/probe` ping under `Probe.*` — the status is read, the device model is neither downloaded in full nor parsed (review 2026-10-21 T-7; it used to parse the whole model every tick) | Consumed — feeds `/hosts` (see [Known limitations](#known-limitations)) |
|
||||
| `IHostConnectivityProbe` | periodic headers-only `/probe` ping under `Probe.*` — the status is read, the device model is neither downloaded in full nor parsed (review 2026-10-21 T-7; it used to parse the whole model every tick). Trade-off: a 200 from something that is not an Agent (a proxy's HTML page) now reads as reachable; the data paths still fail on it | Consumed — feeds `/hosts` (see [Known limitations](#known-limitations)) |
|
||||
| `IRediscoverable` | watches the Agent's `Header.instanceId` | No consumer wires it today — see [Known limitations](#known-limitations) |
|
||||
| `IDriverDiagnostics` | `GetDiagnostics()` — `/sample` effective count, lag, saturated chunks, count raises | Shown on `/hosts` (review 2026-10-21 T-5) |
|
||||
| `IAlarmSource` | CONDITION observations off the same `/sample` pump → Part 9 transitions keyed by the alarm tag's RawPath | Opt-in per raw tag (`alarm` object) — see [CONDITION alarms](#condition-alarms-626) |
|
||||
@@ -118,7 +118,10 @@ correct and tested, just not on the hot path.
|
||||
delivered since it started (a chunk, heartbeat or re-baseline) and its stream is not degraded, a read is answered
|
||||
from the pump's observation index — **read only**; the pump stays its single writer — with no Agent round trip.
|
||||
Otherwise (no subscription, a pump still catching up after a resubscribe, a degraded stream) it falls back to one
|
||||
`/current`, whose per-batch index is now built over a tag map frozen once per binding. A served read also clears a
|
||||
`/current`, whose per-batch index is now built over a tag map frozen once per binding. **Stale window:** a
|
||||
stream that stalls without failing (no chunk, no heartbeat) still serves Good reads from the index until the client's
|
||||
idle watchdog fires (2 × `HeartbeatMs` + `RequestTimeoutMs`) — the same bounded window subscriptions already have. During
|
||||
an Agent-restart re-baseline reads fall back to `/current`. A served read also clears a
|
||||
read-path degradation an earlier failed `/current` left (the read path is answering). The `/current` fallback now
|
||||
checks the answer's `instanceId`: a changed one (an Agent restart seen by a browse-only driver with no pump) drops the
|
||||
cached `/probe` model and raises `OnRediscoveryNeeded` once per distinct id — it used to be detected only by the pump.
|
||||
@@ -349,7 +352,9 @@ and whether it was **saturated** (carried the full `count`). Three consecutive s
|
||||
unknown) lag reopen the stream at the cursor reached with `count` doubled, up to 16× `SampleCount` (max 65 536). A
|
||||
raised stream that delivers nothing (an Agent refusing the larger count) steps back to the last count that delivered
|
||||
and stops raising; at the ceiling a still-behind stream logs one Warning per pump. Every new pump starts from the
|
||||
configured `SampleCount`. The driver now implements `IDriverDiagnostics`: `sampleCount` (effective), `sampleLag`,
|
||||
configured `SampleCount`. An Agent that refuses the raised count with an `MTConnectError` under HTTP 200 goes through
|
||||
the ordinary unusable-answer path first — one transient Degraded blip and a backoff — before the step-back. The
|
||||
driver now implements `IDriverDiagnostics`: `sampleCount` (effective), `sampleLag`,
|
||||
`sampleSaturatedChunks` and `sampleCountRaises` ride the `/hosts` diagnostics bag.
|
||||
|
||||
**A pump carries the session generation it was started against (review 2026-10-21 T-1).** A lifecycle restart
|
||||
@@ -441,7 +446,9 @@ go out as one `POST {agent}/{device}?id1=v1&id2=v2…` per device (the Agent's P
|
||||
several pairs) instead of one POST per slot. A batch closes at a slot naming another device or
|
||||
repeating a DataItem already in it, so two writes to one DataItem still land in request order.
|
||||
An Agent refusal of a multi-slot request is retried slot by slot, so a refused DataItem costs
|
||||
only its own slot (`BadCommunicationError`); a transport failure fails that request's slots.
|
||||
only its own slot (`BadCommunicationError`); a transport failure fails that request's slots. An Agent may apply
|
||||
some pairs of a multi-pair PUT before refusing it, so the per-slot retry can re-send a pair that already landed —
|
||||
harmless for value-setting (the Agent drops an identical repeat).
|
||||
|
||||
**Device resolution needs no extra config.** `TagBinding.WriteTargetsByDataItemId`,
|
||||
built at bind time from a walk of the cached probe model, remembers which device declared
|
||||
|
||||
Reference in New Issue
Block a user