Skip to content

Commit

Permalink
Merge pull request #339 from fronzbot/retry-options
Browse files Browse the repository at this point in the history
Retry options
  • Loading branch information
fronzbot authored Jul 20, 2020
2 parents f88dbda + fe8eac3 commit 9d81973
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
9 changes: 7 additions & 2 deletions blinkpy/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,20 @@ def header(self):
return None
return {"TOKEN_AUTH": self.token}

def create_session(self):
def create_session(self, opts=None):
"""Create a session for blink communication."""
if opts is None:
opts = {}
backoff = opts.get("backoff", 1)
retries = opts.get("retries", 3)
retry_list = opts.get("retry_list", [429, 500, 502, 503, 504])
sess = Session()
assert_status_hook = [
lambda response, *args, **kwargs: response.raise_for_status()
]
sess.hooks["response"] = assert_status_hook
retry = Retry(
total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504]
total=retries, backoff_factor=backoff, status_forcelist=retry_list
)
adapter = HTTPAdapter(max_retries=retry)
sess.mount("https://", adapter)
Expand Down
23 changes: 23 additions & 0 deletions docs/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,29 @@ By default, the ``blink.auth.Auth`` class creates its own websession via its ``c
blink.auth = Auth()
blink.auth.session = YourCustomSession
Custom Retry Logic
--------------------
The built-in auth session via the ``create_session`` method allows for customizable retry intervals and conditions. These parameters are:

- retries
- backoff
- retry_list

``retries`` is the total number of retry attempts that each http request can do before timing out. ``backoff`` is a parameter that allows for non-linear retry times such that the time between retries is backoff*(2^(retries) - 1). ``retry_list`` is simply a list of status codes to force a retry. By default ``retries=3``, ``backoff=1``, and ``retry_list=[429, 500, 502, 503, 504]``. To override them, you need to add you overrides to a dictionary and use that to create a new session with the ``opts`` variable in the ``create_session`` method. The following example can serve as a guide where only the number of retries and backoff factor are overridden:

.. code:: python
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
blink = Blink()
blink.auth = Auth()
opts = {"retries": 10, "backoff": 2}
blink.auth.session = blink.auth.create_session(opts=opts)
Custom HTTP requests
---------------------
In addition to custom sessions, custom blink server requests can be performed. This give you the ability to bypass the built-in ``Auth.query`` method. It also allows flexibility by giving you the option to pass your own url, rather than be limited to what is currently implemented in the ``blinkpy.api`` module.
Expand Down
43 changes: 43 additions & 0 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,49 @@ def test_query_retry_failed(self, mock_refresh, mock_validate):
mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed]
self.assertEqual(self.auth.query(url="http://example.com"), None)

def test_default_session(self):
"""Test default session creation."""
sess = self.auth.create_session()
adapter = sess.adapters["https://"]
self.assertEqual(adapter.max_retries.total, 3)
self.assertEqual(adapter.max_retries.backoff_factor, 1)
self.assertEqual(
adapter.max_retries.status_forcelist, [429, 500, 502, 503, 504]
)

def test_custom_session_full(self):
"""Test full custom session creation."""
opts = {"backoff": 2, "retries": 10, "retry_list": [404]}
sess = self.auth.create_session(opts=opts)
adapter = sess.adapters["https://"]
self.assertEqual(adapter.max_retries.total, 10)
self.assertEqual(adapter.max_retries.backoff_factor, 2)
self.assertEqual(adapter.max_retries.status_forcelist, [404])

def test_custom_session_partial(self):
"""Test partial custom session creation."""
opts1 = {"backoff": 2}
opts2 = {"retries": 5}
opts3 = {"retry_list": [101, 202]}
sess1 = self.auth.create_session(opts=opts1)
sess2 = self.auth.create_session(opts=opts2)
sess3 = self.auth.create_session(opts=opts3)
adapt1 = sess1.adapters["https://"]
adapt2 = sess2.adapters["https://"]
adapt3 = sess3.adapters["https://"]

self.assertEqual(adapt1.max_retries.total, 3)
self.assertEqual(adapt1.max_retries.backoff_factor, 2)
self.assertEqual(adapt1.max_retries.status_forcelist, [429, 500, 502, 503, 504])

self.assertEqual(adapt2.max_retries.total, 5)
self.assertEqual(adapt2.max_retries.backoff_factor, 1)
self.assertEqual(adapt2.max_retries.status_forcelist, [429, 500, 502, 503, 504])

self.assertEqual(adapt3.max_retries.total, 3)
self.assertEqual(adapt3.max_retries.backoff_factor, 1)
self.assertEqual(adapt3.max_retries.status_forcelist, [101, 202])


class MockSession:
"""Object to mock a session."""
Expand Down

0 comments on commit 9d81973

Please sign in to comment.