Audited the registration and mapping code of each app at its origin default branch: OtOpcUa c904472a, MxAccessGateway de86f8b8, ScadaBridge c7d868c5, HistorianGateway 4d6a9ad (all on Health 0.3.0, all MapZbHealth with default paths: /healthz runs nothing, /health/ready and /health/active by tag). GAPS.md now carries the verified per-endpoint coverage matrix and a SPEC-by-app table; each current-state doc lists exactly what each endpoint runs, and HistorianGateway gets its first current-state doc. Recorded: mxaccessgw#206 (worker-executable + galaxy-sql readiness checks, on /health/ready) is merged; historiangw#87 (session-pool check latches 503 until restart) is still open at 4d6a9ad. Deferred P2 downstream probes are now per-app; ScadaBridge IActiveNodeGate unification stays deferred (shared rule already used, only the interface is local). Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
4.4 KiB
Health — current state: MxAccessGateway
Verified 2026-11-09 at mxaccessgw@de86f8b8 (origin/main) for scadaproj#11. Read-only git grep /
git show against the origin default branch; all paths relative to the repo root
(~/Desktop/MxAccessGateway). The pre-adoption state (verified 2026-06-01: a hardcoded /health/live
MapGet, a dead AddHealthChecks(), no probes) is gone; see git history of this file.
- Package:
ZB.MOM.WW.Health0.3.0, core only (src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj:20). No.Akka, no.EntityFrameworkCore— the gateway has no Akka cluster and no EF context. - Registration:
builder.Services.AddGatewayHealthChecks()(GatewayApplication.cs:118) →src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayHealthCheckExtensions.cs:19-41. - Mapping:
endpoints.MapZbHealth()with default paths/writer (GatewayApplication.cs:346), anonymous unconditionally (the Overview dashboard polls/health/activewithout credentials).
Per-endpoint contents
| Endpoint | Checks run | Can return 503 when |
|---|---|---|
/healthz (live) |
none (_ => false) |
never (process up) |
/health/ready |
auth-store, worker-executable, galaxy-sql |
auth SQLite unreachable; worker exe missing; Galaxy SQL unreachable or > 5 s |
/health/active |
mxaccess-sessions |
every open session is Faulted (zero sessions = Healthy) |
No check is tagged live (asserted by GatewayHealthCheckRegistrationTests).
Checks
All registered with AddTypeActivatedCheck, failureStatus: null (the check's own status is used).
Files under src/ZB.MOM.WW.MxGateway.Server/Diagnostics/.
| Name | Class | Tag | Probes | Failure |
|---|---|---|---|---|
auth-store |
AuthStoreHealthCheck |
ready | Opens the API-key SQLite store via AuthSqliteConnectionFactory, runs SELECT 1 |
Unhealthy |
worker-executable |
WorkerExecutableHealthCheck |
ready | File.Exists(Path.GetFullPath(MxGateway:Worker:ExecutablePath)) — same resolution as WorkerProcessLauncher.ResolveExecutablePath |
Unhealthy (missing or invalid path) |
galaxy-sql |
GalaxySqlHealthCheck |
ready | IGalaxyRepository.TestConnectionAsync bounded by a 5 s TimeProvider timeout |
Unhealthy (false, throw, or timeout) |
mxaccess-sessions |
SessionHealthCheck |
active | Buckets ISessionRegistry.Snapshot() by state; data = total/ready/faulted/starting/closing |
Healthy if 0 faulted (incl. 0 sessions); Degraded if some faulted; Unhealthy if all usable sessions faulted |
worker-executable and galaxy-sql are new on main 8c21678c (mxaccessgw#206, closed 2026-11-09).
They check that the worker binary exists and that Galaxy SQL answers; neither checks a running
worker or the named-pipe IPC (workers are per-session and only exist while a client holds a session).
No LDAP check was added (#206 comment: deliberately out of scope).
galaxy-sql is unconditional: AddZbGalaxyRepository is always registered (GatewayApplication.cs:167),
so a gateway whose Galaxy SQL is down drops out of readiness even though its MXAccess data path does not
use SQL. That is the #206 design ("must take the gateway out of rotation"), not an accident.
Active-node gating
None. The gateway is a singleton per host (no cluster), registers no IActiveNodeGate, and uses no
RequireActiveNode(). The active tier is used for a session-health signal instead of an
active/standby signal, so every gateway answers 200 on /health/active unless all its sessions are
faulted.
Other endpoints
MapZbMetrics() (:347, anonymous by default, see MetricsOptions), MapZbGalaxyRepository() (:359),
dashboard routes. No bespoke health endpoint remains.
vs SPEC
| SPEC | Status | Note |
|---|---|---|
§1 three tiers via MapZbHealth, canonical tags |
✅ | default paths |
§1 nothing on live |
✅ | test-asserted |
§2.1 DatabaseHealthCheck<T> |
n/a | no EF; custom SQLite + Galaxy SQL checks |
§2.3 active tier = oldest Up member |
🟡 deviation | no cluster; active tier carries mxaccess-sessions (deliberate, documented in SessionHealthCheck) |
§2.4 GrpcDependencyHealthCheck for the worker |
⛔ not used | worker IPC is named pipes, not gRPC; worker-executable is a presence proxy (see GAPS P2) |
| §3 canonical JSON writer | ✅ | MapZbHealth default |
§4 IActiveNodeGate |
n/a | no active/standby |