tlyakhov / python-decora_wifi

Python Library for Interacting with Leviton Decora Smart WiFi Switches & Dimmers
MIT License
37 stars 21 forks source link

Add 15sec request timeout to all API calls, fixing indefinite hangs #22

Open mitchsw opened 1 year ago

mitchsw commented 1 year ago

Objective

This PR adds a 15 second timeout to all API requests to Leviton. As per the requests lib docs, a call may hang indefinitely without a timeout. A timeout will improve the reliability of always-on applications of the decora_wifi lib.

Motivation

I use this library as part of homeassistant. I have found very rarely (once every 2 months or so) that the decora_wifi integration can break. Attaching a python debugger, I find a worker thread stuck indefinitely in the following stacktrace:

read (ssl.py:1134)
recv_into (ssl.py:1278)
readinto (socket.py:706)
_update_chunk_length (response.py:758)
read_chunked (response.py:828)
stream (response.py:624)
generate (models.py:816)
content (models.py:899)
send (sessions.py:747)
request (sessions.py:589)
get (sessions.py:602)
call_api (__init__.py:48)
refresh (iot_switch.py:87)
update (homeassistant/components/decora_wifi/light.py:172)
run (thread.py:58)
_worker (thread.py:83)
run (threading.py:975)
_bootstrap_inner (threading.py:1038)
_bootstrap (threading.py:995)

With this PR, I believe the flaky call_api() would timeout instead of getting stuck, and the following homeassistant update loop would hopefully succeed.

Implementation

15 seconds should surely be enough for any call. I looked if I could attach a timeout to the requests.Session, but that appears to not be possible.