-
-
Notifications
You must be signed in to change notification settings - Fork 90
Axle retry logic, move Fox, Axle, Octopus and GE over to aiohttp #3116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds retry logic with exponential backoff to the Axle Energy VPP API integration to improve resilience against transient network errors. The implementation distinguishes between retryable errors (connection issues) and non-retryable errors (authentication failures, JSON parsing errors).
Key Changes
- Implemented
_request_with_retry()method with exponential backoff (1s, 2s) for RequestException errors - Refactored
fetch_axle_event()to use the new retry mechanism - Added comprehensive test coverage for retry behavior, including success after retries
- Updated version to v8.30.7
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/predbat/axle.py | Added _request_with_retry() method with exponential backoff retry logic; refactored fetch_axle_event() to use new retry mechanism; added exception handling in run() method |
| apps/predbat/tests/test_axle.py | Added two new test cases: test_axle_retry_success_after_failure() to verify successful retry after initial failures, and test_axle_json_parse_error() to verify no retry on JSON parse errors; updated existing tests to verify retry behavior |
| apps/predbat/unit_test.py | Registered two new test functions in imports and test execution list |
| apps/predbat/predbat.py | Incremented version from v8.30.6 to v8.30.7 |
| apps/predbat/web.py | Simplified unhealthy status message by removing redundant "Predbat not running" text |
| Args: | ||
| url: URL to request | ||
| headers: Request headers | ||
| max_retries: Maximum number of retry attempts (default: 3) |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter description is ambiguous. The parameter name 'max_retries' suggests it's the number of retries after the first attempt, but it actually represents the total number of attempts (including the initial attempt). For example, max_retries=3 means 3 total attempts (1 initial + 2 retries). Consider clarifying the docstring to say "Maximum number of attempts (default: 3)" or renaming the parameter to 'max_attempts' for clarity.
| max_retries: Maximum number of retry attempts (default: 3) | |
| max_retries: Maximum number of attempts, including the initial request (default: 3) |
| data = self._request_with_retry(url, headers) | ||
| if data is None: | ||
| self.log("Axle API: Warn: No event data in response") | ||
| self.failures_total += 1 |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the request fails (data is None), the publish_axle_event() method is not called, which means the binary sensor won't be updated to reflect the failure state. This is inconsistent with the success path (lines 221-222) where publish_axle_event() is always called. Consider calling publish_axle_event() here to ensure the sensor state is always consistent, even after failures.
| self.failures_total += 1 | |
| self.failures_total += 1 | |
| self.publish_axle_event() |
| return None | ||
| except requests.RequestException as e: | ||
| if attempt < max_retries - 1: | ||
| sleep_time = 2**attempt # Exponential backoff: 1s, 2s, 4s |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment states "Exponential backoff: 1s, 2s, 4s" but with max_retries=3 (3 attempts total), only 2 sleep periods occur between the 3 attempts. The actual backoff sequence is [1s, 2s] (2^0, 2^1). The third value 4s (2^2) would only occur if there were 4 attempts. Update the comment to reflect the actual behavior: "Exponential backoff: 1s, 2s".
| sleep_time = 2**attempt # Exponential backoff: 1s, 2s, 4s | |
| sleep_time = 2**attempt # Exponential backoff: 1s, 2s |
| else: | ||
| self.log(f"Warn: Axle API: Request failed after {max_retries} attempts: {e}") | ||
| return None | ||
| return None |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This return statement is unreachable. All code paths within the loop either return a value (lines 150, 153, 156, 164) or continue to the next iteration (line 161). The for loop will never complete normally without returning, making this line dead code. Consider removing it to improve code clarity.
| return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
| time.sleep(1) | ||
| await p_han.timer_tick() | ||
| if check_modified(py_files, start_time): | ||
| if (count % 5 == 0) and check_modified(py_files, start_time): |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file change detection now only runs every 5 seconds (when count % 5 == 0). However, if a file is modified between these checks, detection could be delayed up to 5 seconds. This is likely intentional for performance, but consider if this delay is acceptable for development workflows. If instant detection is desired, the check should run every iteration or the modulo divisor should be adjusted.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
No description provided.