Skip to content

fix(client): Improve resilience on transient network and auth failures - #2233

Open
dansrogers wants to merge 4 commits into
iMicknl:mainfrom
dansrogers:fix/transient-error-resilience
Open

dansrogers wants to merge 4 commits into
iMicknl:mainfrom
dansrogers:fix/transient-error-resilience

Conversation

@dansrogers

@dansrogers dansrogers commented Aug 26, 2026

Copy link
Copy Markdown

Summary & Overview

This pull request hardens OverkizClient against transient network drops, socket timeouts, and session expirations. It adds automatic exponential backoff retry decorators to register_event_listener(), introduces defensive error trapping in relogin() and refresh_listener() backoff callbacks, and ensures _event_listener_id is consistently invalidated and reset upon re-authentication.

Motivation & Problem Statement

During periods of network instability or Overkiz/Somfy cloud maintenance:

  1. Unhandled Network Drops during Event Registration: register_event_listener() was only decorated with @retry_on_concurrent_requests. A socket timeout, DNS failure, or transient 401 NotAuthenticatedError during listener registration raised an immediate exception instead of triggering retry backoff and automated session recovery.
  2. Backoff Callback Crashes: In relogin() and refresh_listener() backoff callbacks, if a network outage was ongoing when the backoff handler fired, unhandled ClientError, TimeoutError, or OSError exceptions crashed the backoff lifecycle prematurely.
  3. Stale Listener ID Retention: When re-authenticating after session eviction, a stale _event_listener_id could be retained, preventing clean event listener re-registration.

Changes Made

  • Backoff Retries on register_event_listener():
    Decorated register_event_listener() with @retry_on_connection_failure and @retry_on_auth_error alongside @retry_on_concurrent_requests in pyoverkiz/client.py.
  • Defensive Callback Handlers:
    Wrapped client.login() in relogin() and client.register_event_listener() in refresh_listener() with try/except (TimeoutError, ClientError, OSError) blocks to log warnings without terminating backoff sequences.
  • Listener ID Invalidation:
    • Added public helper reset_event_listener_id(self) -> None on OverkizClient.
    • Added explicit listener ID reset inside login() and within relogin() / refresh_listener() handlers.
  • Test Suite Expansion:
    • Added unit test coverage in tests/test_client.py for retry policies on register_event_listener and error handling during backoff callbacks.
    • Added comprehensive adversarial test suite in tests/test_adversarial_transport_auth.py covering cascading faults, prolonged outages, 502/503 server maintenance, and fast-failure on non-retryable bad credentials (BadCredentialsError).

Test Coverage & Verification

  • Full Test Suite: 570+ tests passed.
  • Static Analysis & Pre-commit: All 11 prek / ruff / mypy / ty checks passed cleanly.
============================= test session starts ==============================
collected 570 items
570 passed

Pre-commit & Static Analysis Verification Log

ruff check...............................................................Passed
ruff format..............................................................Passed
trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
check json...............................................................Passed
check yaml...............................................................Passed
check for added large files..............................................Passed
don't commit to branch...................................................Passed
Lint GitHub Actions workflow files.......................................Passed
mypy.....................................................................Passed
ty check.................................................................Passed

Cross-Repository Context & Companion PR

  • Home Assistant Core Companion PR: fix(overkiz): Improve coordinator resilience against transient connectivity and auth errors home-assistant/core#180222
  • Defense-in-Depth Architecture:
    • Layer 1 (This PR - python-overkiz-api): Hardens low-level HTTP transport retries, session backoff, and event listener lifecycle management.
    • Layer 2 (Downstream - home-assistant/core): Implements coordinator state self-healing, execution TTL cleanup (EXECUTION_TTL = 60s), and full device state resynchronization (_need_full_resync).
  • Decoupled Deployment: This PR does not alter public API signatures and maintains 100% backward compatibility with existing downstream consumers. Downstream integrations can take advantage of these resilience enhancements immediately upon package update.

@iMicknl iMicknl added the bug Something isn't working label Sep 2, 2026
iMicknl added a commit that referenced this pull request Sep 5, 2026
Fork pull requests currently fail the Release Drafter autolabel check
with `Resource not accessible by integration`: GitHub downgrades the
`pull_request` token to read-only, preventing the action from applying
labels (as seen in #2233).

Use `pull_request_target` and update the autolabel job condition so fork
PRs can receive Conventional Commit labels. The job retains only
`contents: read` and `pull-requests: write`, uses the existing
SHA-pinned action, and does not check out or execute contributor code.
Release drafting remains restricted to pushes to main.

Validation: all pre-commit checks passed, including actionlint, mypy,
and ty; 556 tests passed. Pytest printed an unclosed client session
message at shutdown. Live fork-event validation requires this workflow
change to reach main, followed by a new PR event.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants