Repository navigation
fix: add timeout to requests.get() in futurerate.py and octopus.py - #4539
Conversation
… to prevent silent TCP stalls from hanging the main loop indefinitely Fixes #4525 - a stalled Nord Pool connection would block the main prediction loop forever. With timeout=30, the existing exception handler will catch requests.exceptions.Timeout and fall back to cached rates via the existing retry logic. Also adds timeout to octopus.py download_octopus_free_func() which had the same pattern. Co-authored-by: springfall2008 <48591903+springfall2008@users.noreply.github.com>
|
@copilot I changed this to 120 seconds to allow more margin, but you haven't written any tests to cover this change |
There was a problem hiding this comment.
Pull request overview
This PR aims to prevent the main Predbat prediction loop from hanging indefinitely when external HTTP endpoints stall (notably Nord Pool and Octopus free-session endpoints), by adding explicit requests.get() timeouts so the existing fallback-to-cache paths can execute.
Changes:
- Added a timeout to
requests.get()in the Octopus “free sessions” downloader. - Added a timeout to
requests.get()in the FutureRate (Nord Pool) downloader (but the configured value currently differs from the PR description).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
apps/predbat/futurerate.py |
Adds a requests.get() timeout to bound Nord Pool fetch duration (currently set to 120s, not 30s as described). |
apps/predbat/octopus.py |
Adds a requests.get() timeout for Octopus free-session downloads, but needs broader exception handling to actually catch timeouts. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: springfall2008 <48591903+springfall2008@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (2)
apps/predbat/octopus.py:2072
requests.get(..., timeout=120)can raiserequests.exceptions.Timeout(and otherRequestExceptions), but this function only catchesConnectionError. That means a stalled/slow response can still bubble up and potentially break the calling loop instead of cleanly logging + returningNoneas intended.
try:
r = requests.get(url, timeout=120)
except requests.exceptions.ConnectionError:
self.log("Warn: Octopus: Unable to download Octopus data from URL {} (ConnectionError)".format(url))
self.record_status("Warn: Unable to download Octopus free session data", debug=url, had_errors=True)
apps/predbat/futurerate.py:416
- PR description/issue text says the new safeguard is
timeout=30, but the code usestimeout=120here (and tests assert 120). If 120s is intentional, the PR description (and issue’s suggested fix) should be updated; if the intent is 30s (or a(connect, read)tuple), the code/tests should be aligned so the main loop is bounded as described.
def download_futurerate_data_func(self, url):
try:
r = requests.get(url, timeout=120)
except Exception as e:
A silent TCP stall (connection established, no response) on the Nord Pool fetch blocks the main prediction loop indefinitely — no exception is raised, so the existing
try/exceptnever fires and the loop hangs until manual restart. Inverter stays latched in its last commanded state.Changes
futurerate.py— addtimeout=30torequests.get()indownload_futurerate_data_func(primary fix)octopus.py— same fix indownload_octopus_free_func, which had the identical barerequests.get(url)patternrequests.exceptions.Timeoutis a subclass ofException, so the existingexcept Exceptionhandler in both functions catches it, logs a warning, and falls back to cached rates — no new error-handling code required.