Skip to content

feat(config): retry validate_config() after a failure, self-healing (#4379) - #4394

Open
chalfontchubby wants to merge 1 commit into
springfall2008:mainfrom
chalfontchubby:feat/validate-config-retry
Open

feat(config): retry validate_config() after a failure, self-healing (#4379)#4394
chalfontchubby wants to merge 1 commit into
springfall2008:mainfrom
chalfontchubby:feat/validate-config-retry

Conversation

@chalfontchubby

Copy link
Copy Markdown
Collaborator

Summary

validate_config() only ran at startup and when config actually changed - never periodically. If a sensor mapped in apps.yaml wasn't populated yet at that exact moment (e.g. a slower-starting integration during an HA restart), Predbat correctly logged a config error - but if that sensor came good on its own a few seconds later, nothing re-validated, so the stale "config invalid" status just sat there until the next manual restart.

  • Adds validate_config_schedule_retry() (called right after every validate_config() call site with its error count) and validate_config_check_retry() (checked once per tick from the existing 15-second update_time_loop()).
  • Retries only ever start following an actual validation failure - a clean validation never arms anything, matching the ask on Config validation status can go stale after a self-healed startup race #4379.
  • Default: 2 retries, 1 minute apart. A retry that comes back clean clears the sequence immediately. A retry that's still failing decrements the counter and reschedules; once retries are exhausted it gives up quietly until the next restart or config change (the pre-existing behaviour).
  • New apps.yaml-only settings (not HA-exposed, matching the shape of balance_inverters_seconds): validate_config_retries (default 2, set to 0 to disable and revert to the old behaviour) and validate_config_retry_minutes (default 1).
  • No new scheduler primitive - this AppDaemon-shim codebase (hass.py) only has run_every(), no one-shot delayed-callback API, so this piggybacks on the existing 15-second loop rather than registering a new timer.

Test plan

  • ./run_pre_commit (via coverage/run_pre_commit) - all hooks pass
  • New test_validate_config_retry covers: clean validation never arms a retry; default retry count/interval; no premature retry before the due time; still-failing retries decrement and reschedule; exhausting retries gives up cleanly (and doesn't fire again afterwards); a successful retry clears the sequence immediately rather than just decrementing; validate_config_retries: 0 disables the feature; custom retry count/interval are respected
  • Existing test_validate_config still passes unchanged
  • Full quick suite (./run_all --quick) passes

Addresses #4379

…pringfall2008#4379)

validate_config() only ran at startup and on config change, never
periodically - so a transient race (a slow-starting integration's
sensor not populated yet at that exact moment) left a stale "config
invalid" status sitting until the next manual restart, even though
apps.yaml was actually fine moments later.

Adds validate_config_schedule_retry()/validate_config_check_retry():
after any validate_config() call that finds errors, arms a retry
sequence (default 2 retries, 1 minute apart, both configurable via
apps.yaml). Retries only ever start following an actual failure - a
clean validation never triggers one. A retry that comes back clean
clears the sequence immediately; one that's still failing decrements
the counter and reschedules, giving up quietly once retries are
exhausted. Checked once per tick from the existing 15-second
update_time_loop() rather than registering a new scheduler primitive -
this AppDaemon-shim codebase only has run_every(), no one-shot
delayed-callback API to build on.

New apps.yaml-only settings (APPS_SCHEMA, not HA-exposed):
validate_config_retries (default 2, 0 disables), validate_config_retry_minutes
(default 1).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

The retry scheduler does not reliably disable/cancel an already-armed retry sequence when validate_config_retries is set to 0, and the new test doesn’t currently catch that case.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

This PR adds a self-healing retry mechanism for apps.yaml configuration validation so transient startup races (e.g., sensors not populated yet during an HA restart) can clear stale “config invalid” status without requiring a manual restart.

Changes:

  • Adds validate_config_schedule_retry() and validate_config_check_retry() to retry validation only after a failure, driven by the existing 15-second update_time_loop().
  • Introduces new apps.yaml settings validate_config_retries and validate_config_retry_minutes (documented and added to schema).
  • Adds a new unit test (test_validate_config_retry) and registers it in the test runner.
File summaries
File Description
docs/apps-yaml.md Documents the new config validation retry settings and behavior.
apps/predbat/unit_test.py Registers the new validate_config_retry test in the test runner.
apps/predbat/tests/test_validate_config.py Adds coverage for the retry scheduling/check logic via a new test.
apps/predbat/predbat.py Implements retry state, scheduling, and periodic checking; wires it into existing validate call sites and the 15s loop.
apps/predbat/config.py Adds schema entries for the two new apps.yaml settings.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread apps/predbat/predbat.py
Comment on lines +1513 to +1521
if errors:
retries = self.get_arg("validate_config_retries", 2)
if retries > 0:
self.validate_config_retries_remaining = retries
retry_minutes = self.get_arg("validate_config_retry_minutes", 1)
self.validate_config_next_retry_time = self.now_utc + timedelta(minutes=retry_minutes)
else:
self.validate_config_retries_remaining = 0
self.validate_config_next_retry_time = None
Comment on lines +444 to +448
# validate_config_retries: 0 disables the feature entirely
my_predbat.args["validate_config_retries"] = 0
my_predbat.validate_config_schedule_retry(1)
assert my_predbat.validate_config_retries_remaining == 0, "validate_config_retries=0 should disable retries"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants