refactor(drivers): delete the inert driver-tier recycle machinery (#522)
The tier system was documented, operator-authorable, and inert. Deleted rather than activated,
because its premise is gone rather than merely unused.
"Tier C" meant a driver running out-of-process behind an IDriverSupervisor that could restart its
Host without tearing down the OPC UA session. No such process exists anywhere: Galaxy reaches
MXAccess over gRPC to the external mxaccessgw sidecar (PR 7.2 retired the in-process
Galaxy.Host/Proxy/Shared projects) and FOCAS has run in-process since its managed wire client
landed 2026-04-24. Consistently, IDriverSupervisor had ZERO implementations and there was nothing
for one to implement against.
The issue understated the inertness. It says the Tier-C-only protections never engaged, implying
the Tier A/B parts did. They did not: nothing constructs MemoryTracking, MemoryRecycle or
ScheduledRecycleScheduler outside their own unit tests, so the whole Core/Stability recycle layer
was dead — meaning option (a), "pass real tiers", was never a flag flip. It would have meant
writing the wiring that never existed AND arming it.
Deleted: MemoryTracking, MemoryRecycle, ScheduledRecycleScheduler, IDriverSupervisor, the
vestigial DriverTypeRegistry (referenced only by its own tests), and the RecycleIntervalSeconds
knob — which the AdminUI let an operator author and the parser validated while it configured
nothing.
DriverTier itself SURVIVES and is load-bearing: DriverResilienceOptions.GetTierDefaults supplies
the real per-capability timeout/retry/breaker policies via DriverFactoryRegistry.GetTier and
DriverCapabilityInvokerFactory. Only the isolation-and-recycle layer above it is gone.
Deliberately NOT deleted:
- WedgeDetector came along in the same directory and is equally dead in production, but it is
tier-agnostic and is not recycle machinery — it only shares the folder. Restored rather than
swept up in a decision that was not about it.
- IDriver.GetMemoryFootprint() and FlushOptionalCachesAsync() lose their only consumer here.
Removing them touches all 12 drivers and every test stub, so they are documented as
consumerless and filed as #525 instead of buried in this diff.
Compatibility: a deployed ResilienceConfig blob still carrying "recycleIntervalSeconds" parses
cleanly (unknown keys are ignored — guarded by a new test, because a blob that suddenly failed to
parse would fall back to tier defaults and silently discard the operator's real overrides), and
the AdminUI's preserve-unknown-keys bag keeps the key rather than rewriting stored config on an
unrelated edit.
The 01/U-6 knob-inertness guard carried an explicit carve-out admitting RecycleIntervalSeconds was
dormant and out of scope; that carve-out is now gone, so the expected set is literally what the
test's name claims.
Note: Host.IntegrationTests has 2 failures (DriverProbeRegistrationTests.is_idempotent,
PrimaryGateFailoverTests) — verified pre-existing by reproducing both on clean master dc9d947b.
Claude-Session: https://claude.ai/code/session_015p7wGqy3YpZNCpDzTpGMKo
This commit is contained in:
+33
-25
@@ -106,37 +106,45 @@ calls `AddOtOpcUaDriverProbes` in the `hasAdmin` block, and
|
||||
|
||||
---
|
||||
|
||||
## IDriverSupervisor — Tier C out-of-process recycle
|
||||
## IDriverSupervisor / process recycle — REMOVED (Gitea #522)
|
||||
|
||||
[`Core.Abstractions/IDriverSupervisor.cs`](../src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/IDriverSupervisor.cs)
|
||||
`IDriverSupervisor`, `MemoryRecycle`, `MemoryTracking` and
|
||||
`ScheduledRecycleScheduler` **no longer exist.** This section used to describe
|
||||
them as the Tier C protection layer.
|
||||
|
||||
The process-level supervisor contract a **Tier C** (out-of-process) driver's
|
||||
topology provides. Its concern is restarting the out-of-process Host when a
|
||||
hard fault is detected (memory breach, wedge, scheduled recycle window). Tier
|
||||
A/B drivers run in-process and do **not** have a supervisor — recycling them
|
||||
would kill every OPC UA session and every co-hosted driver. The Core.Stability
|
||||
layer only invokes this interface after asserting the tier.
|
||||
They were removed because the thing they acted on is gone. "Tier C" meant a
|
||||
driver running **out-of-process behind a supervisor that could restart its Host**
|
||||
without tearing down the OPC UA session or co-hosted drivers. No such process
|
||||
remains anywhere: Galaxy reaches MXAccess over gRPC to the external
|
||||
`mxaccessgw` sidecar (PR 7.2 retired the in-process `Galaxy.Host` / `Proxy` /
|
||||
`Shared` projects), and FOCAS has run in-process since its managed wire client
|
||||
landed 2026-04-24. Consistent with that, `IDriverSupervisor` had **zero
|
||||
implementations**, and `MemoryTracking` / `MemoryRecycle` /
|
||||
`ScheduledRecycleScheduler` were constructed **only in their own unit tests** —
|
||||
so this was not dormant-but-ready code, it was code with no path to running.
|
||||
|
||||
Members:
|
||||
The operator-facing half went too: `RecycleIntervalSeconds` was authorable
|
||||
through the AdminUI's driver resilience section and validated by the parser
|
||||
while configuring nothing. A stored `ResilienceConfig` still carrying the key
|
||||
parses cleanly (unknown keys are ignored) and the AdminUI preserves it rather
|
||||
than silently rewriting an operator's config.
|
||||
|
||||
- `string DriverInstanceId { get; }` — the driver instance this supervisor
|
||||
governs.
|
||||
- `Task RecycleAsync(string reason, CancellationToken cancellationToken)` —
|
||||
request a terminate+restart of the Host process; implementations are
|
||||
expected to be idempotent under repeat calls during an in-flight recycle.
|
||||
**`DriverTier` itself survives and is load-bearing** — do not delete it while
|
||||
following this note. `DriverResilienceOptions.GetTierDefaults(tier)` supplies
|
||||
the real per-capability timeout / retry / breaker policies, resolved via
|
||||
`DriverFactoryRegistry.GetTier` and applied by `DriverCapabilityInvokerFactory`.
|
||||
Every driver runs Tier A because no factory passes a tier, so today that means
|
||||
one uniform policy set.
|
||||
|
||||
Callers (both in
|
||||
[`Core/Stability/`](../src/Core/ZB.MOM.WW.OtOpcUa.Core/Stability/)):
|
||||
⚠️ Two `IDriver` members are now **consumerless**: `GetMemoryFootprint()` and
|
||||
`FlushOptionalCachesAsync()` existed to feed `MemoryTracking`. All 12 drivers
|
||||
still implement them and nothing calls them. They were left in place rather
|
||||
than swept, since removing them touches every driver and every test stub —
|
||||
tracked as Gitea **#525**.
|
||||
|
||||
- `ScheduledRecycleScheduler`
|
||||
([`Core/Stability/ScheduledRecycleScheduler.cs`](../src/Core/ZB.MOM.WW.OtOpcUa.Core/Stability/ScheduledRecycleScheduler.cs))
|
||||
— opt-in periodic recycle. A `TickAsync` method advanced by the caller's
|
||||
ambient scheduler decides whether the configured interval has elapsed and, if
|
||||
so, drives `RecycleAsync`. Its constructor throws unless the tier is C, making
|
||||
in-process misuse structurally impossible.
|
||||
- `MemoryRecycle`
|
||||
([`Core/Stability/MemoryRecycle.cs`](../src/Core/ZB.MOM.WW.OtOpcUa.Core/Stability/MemoryRecycle.cs))
|
||||
— on a memory hard-breach, calls `RecycleAsync` (when a supervisor is wired).
|
||||
If per-driver memory protection is wanted again, build it for the architecture
|
||||
as it is now: a process-wide watchdog, not a per-driver tier whose only remedy
|
||||
requires a supervisor that cannot exist in-process.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user