IHostConnectivityProbe / DriverHostStatus: dead surface — build the publisher or delete it #521
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of
deferment.md§3.2 / Gitea #518. TheIRediscoverablehalf of #518 is fixed —DriverInstanceActornow consumes it and surfaces a re-browse prompt on/hosts. This tracks the other half, which is a keep-or-delete decision, not a bug.What is true today
IHostConnectivityProbeis implemented by 11 drivers (Modbus, FOCAS, TwinCAT, OpcUaClient, AbLegacy, S7, Sql, Galaxy, MTConnect, Mqtt, AbCip).GetHostStatuses()has zero production call sites. The only non-driver references are the interface declaration and a comment inUnwrappedCapabilityCallAnalyzerexplaining why the analyzer exempts it.OnHostStatusChangedhas exactly one+=insrc/—GalaxyDriver.cs:221, which is intra-driver (its aggregator re-raising onto its own interface). Every other subscription is intests/.DriverHostStatusentity + DbSet + table exist and nothing ever writes a row. EveryDriverHostStatusesreference in the repo is the DbSet declaration plusDriverHostStatusTests.OnHostStatusChangedand upserts rows on transitions + periodic liveness heartbeats."DriverInstanceResilienceStatus.cs:12claims "The Admin UI left-joins this table on DriverHostStatus for display" — that join exists in no razor file.There is no permanently-empty UI table.
/hostsreads Akka membership,IDriverStatusSnapshotStoreand ConfigDBClusterNodes/DriverInstances— neverDriverHostStatus. So the dead surface is invisible: an empty table, an unused DbSet, and 11 driver implementations of a method nobody calls.The decision
Do not delete on inference. The table was re-created in the v3 initial migration (
20260715230637_V3Initial.cs:108-121), so someone carried it forward deliberately. Confirm intent first.Either:
(a) Build the missing publisher. A hosted service subscribing to every registered driver's
OnHostStatusChanged, upsertingDriverHostStatusrows on transition plus a liveness heartbeat, and a/hostssection that reads them. This is what the entity doc already describes. Note the two halves are separable —OnHostStatusChanged(the event) is the useful half;GetHostStatuses()(the snapshot pull) is only needed to prime state at startup.(b) Delete it. Drop
GetHostStatuses()from the interface, the 11 driver implementations, the DbSet, the table (migration), andDriverHostStatusTests. Fix the two doc-comments that describe the non-existent publisher and the non-existent Admin UI join.Per-host connectivity is genuinely useful for a multi-device driver (a FOCAS or AbLegacy instance owning several PLCs), where today one unreachable device is invisible behind an otherwise-Healthy driver row. That is the argument for (a).
Resolved on master
abda6f9e— but not the way this issue framed the choice, so the difference is worth recording.Option (a) as written was not buildable
The publisher this issue (and the entity's own doc-comment) describes — driver nodes upserting
DriverHostStatusrows — cannot exist. Per-cluster mesh Phase 4 gatesAddOtOpcUaConfigDbon theadminrole inProgram.cs, so a driver-only node has no ConfigDb connection to write rows with. The design predates that change and was never revisited.So the capability was kept and the transport changed instead.
What shipped
DriverHealthChanged.HostStatusescarries the probe result to/hostsas a Hosts column. That channel already reached the page, already survives the mesh split via the Phase 5 gRPC telemetry stream, and already replays a last-value snapshot on re-subscribe — so per-host state re-primes after a reconnect without a durable store. Both halves of the interface now do what this issue says they are for:OnHostStatusChangedtriggers a prompt publish,GetHostStatuses()is the source of truth.The argument for (a) in the issue is exactly what the column delivers: a multi-device driver stays aggregate-
Healthywhile one of its devices is unreachable, which the driver-level state chip structurally cannot express.Dropped: the
DriverHostStatusentity, enum, DbSet, model config, tests, and table (migrationDropDriverHostStatusTable). Empty on every deployment, so the scaffolder's data-loss warning is moot;Down()recreates it exactly.Two traps, both falsified against the prod code
has_host_statusesflag. Collapsing them would render every probe-less driver as one whose devices are all fine.Live-gated on docker-dev
All three states render against real drivers:
—(Calculation, no probe),1 host(healthy Modbus/Sql),1 / 1 DOWNfor the faulted OpcUaClient with tooltipopc.tcp://10.100.0.35:50000: Unknown since 2026-07-30 08:51:23Z.That tooltip vindicates counting
Unknownas degraded — the faulted driver's probe never completed a tick, so treating Unknown as healthy would have shown the one genuinely broken driver as fine.The cross-mesh gRPC path was verified, not assumed. site-a is a separate Akka mesh, so its telemetry crosses the Phase 5 stream the proto change targets. It first showed
—, which is also what a broken mapper produces; rebuilding site-a turned it into1 host, proving the presence flag round-trips over the real wire and that the—was version skew. Mixed-version fleets therefore degrade to—, not to a false0 hosts.Found en route — filed, not folded in
DriverInstanceResilienceStatusis the identical defect: no writer, no reader, only a DbSet declaration, while the live data rides thedriver-resilience-statustelemetry channel. Its doc-comment now states that instead of describing the sampler and AdminUI join that were never built. Tracked as #524 rather than widening this schema change beyond what was asked.