Repository navigation
Detect frozen PVs with an independent CA context - #50
Merged
Merged
Conversation
IOC and network restarts have historically left PVs "frozen": a monitor that stops delivering while the IOC still serves the PV, which a restart of epics2web fixes. Nothing reported that, so Tomcat is restarted periodically by cron. FrozenPvDetector gives suspicious PVs a short-lived subscription in a second CA context, with its own virtual circuits, made like the monitor's so the IOC applies the same deadband to both. Comparing values instead would mistake a change within a deadband for a missed update. A PV is frozen when its monitor has been disconnected, or still connecting, past the grace period while the independent subscription connects, or when a monitor that used to update has gone quiet and the independent subscription receives a change it doesn't. Only PVs not connected past the grace period, and quiet PVs that have changed before, are probed, at most 20 at a time and each at most once every 30 check intervals. A PV stops being frozen when its monitor gets an update. Detection is report-only: frozen PVs are logged as warnings and listed by /healthcheck, and the default and strict responses are unchanged. ?frozen=true answers 503 when a PV is frozen, for restart automation once it's trusted. FROZEN_CHECK_SECONDS (default 10) sets the check interval, from which the other timings derive, and FROZEN_PV_CHECK=false turns detection off. FrozenPvDetectorTest covers the decisions with a controlled clock. FrozenPvDetectionTest runs the detector against the test IOC with two real CA contexts, and simulates a lost subscription by clearing a monitor's CAJ subscription behind its back. HealthcheckTest checks that working monitors and a stopped IOC aren't reported frozen. Part of #28 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
slominskir
approved these changes
Oct 4, 2026
This was referenced Oct 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 2 of the plan discussed for #28: detect "frozen" PVs, so the periodic Tomcat restart can eventually be replaced by evidence. Report-only for now.
A frozen PV is one whose monitor has stopped working while the IOC still serves it, so restarting epics2web would be expected to fix it. A PV whose IOC is down isn't frozen.
How it works
FrozenPvDetectorruns everyFROZEN_CHECK_SECONDS(default 10). It gives suspicious PVs a short-lived subscription in a second CA context, which has its own virtual circuits. The subscription is made likeChannelMonitor's: same type, count andMonitor.VALUEmask. A PV is frozen when either:DISCONNECTED, or stillCONNECTING, longer than the healthcheck grace period, but the independent subscription connects and receives the PV;Why subscriptions and not value comparison: comparing a fresh read with the monitor's last value would flag PVs with a monitor deadband (
MDEL), whose value can drift within the deadband without an update being posted. Subscriptions made the same way get the same deadband from the IOC.Load: only suspicious PVs are probed, at most 20 at a time, each for at most 6 intervals, and the same PV at most once every 30 intervals. Suspicious means not connected past the grace period, or quiet for 6 intervals after having changed at least once. A PV that has never changed can't show missing updates, so it's never probed. With the defaults, a probe lasts at most 60 s and a PV is re-probed at most every 5 minutes.
Through a gateway: both contexts reach PVs through the gateway, so this finds problems between epics2web and the gateway, not inside the gateway.
A frozen PV stops being frozen when its monitor gets an update.
Reporting
WARNING(PV … is frozen: <reason>), and its recovery atINFO./healthchecklists frozen PVs withfrozen,frozen_minutesandfrozen_reason. They're added to a PV's existing entry, or get an entry of their own if the PV is still marked connected.?strict=trueresponses are unchanged. The new?frozen=trueanswers 503 when any PV is frozen, for restart automation once it's trusted.FROZEN_PV_CHECK=falseturns detection off. The README documents both settings.Suggested rollout
Deploy with the cron restart still in place, and watch the logs for
is frozenwarnings:?frozen=true.Checks
FrozenPvDetectorTest(unit, 11 tests, controlled clock and fake probes) covers:FrozenPvDetectionTest(integration, about 19 s): runs the real detector in the test JVM against the test IOC, with two real CA contexts. For 10 s withHELLO,channel1(never changes) and a missing PV, nothing is flagged. Then the test clearsHELLO's CAJ subscription behind its monitor's back, as a lost subscription would look.HELLO, and onlyHELLO, is then flagged for a missed change. Passed 3 runs in a row.HealthcheckTest:workingMonitorsAreNotFrozen: 10 s ofHELLOandchannel1gives?frozen=true200;channel1isn't flagged frozen, and?frozen=truereturns 200.FROZEN_CHECK_SECONDS: 1, with no frozen warnings in the server log. A hung IOC (docker pausefor 45 s) and an IOC restart weren't flagged either../gradlew spotlessCheck testpasses.🤖 Generated with Claude Code