Orion Client Utilities¶
- class orionclient.utils.Backoff(cap: float = 90.0, base: float = 0.1, backoff_dict: Optional[Dict[int, Tuple[int, int]]] = None)¶
Utility for Jittered Backoff
Instantiate and call sleep() as many times as necessary
Uses the decorrelated jitter backoff mechanism described here: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
default maximum sleep in seconds
default initial sleep in seconds
f: status_code –> (base, cap)
If backoff_dict does not contain a key for a status_code, then the default cap and base are used.
Previously OrionClient was using the same session for interactive and non-interactive sessions this caused problems with timeouts and retries. Now they have seperate sessions, with interactive sessions having shorter timeouts and less retries, and the non-interactive sessions have had their defaults increased.
Given a base backoff of 0.1 seconds, a cap of 90 seconds, and roughly doubling the sleep between each retry 10 attempts will be made in about 192 seconds.
0.2 + 0.4 + 0.8 + 1.6 + 3.2 + 6.4 + 12.8 + 25.6 + 51.2 + 90 = 192.2
A 404 Not Found error will be retried 8 times, or 51 seconds.
A 429 Too Many Requests error will be retried up to 45 times or an hour, whichever is reached first. The additional 35 retries, paced about 90 seconds apart (the cap), will be attempted after the first 10 attempts.
If you wanted to modify the behavior to retry only 300 seconds, you would only need to modify the retry_timeout. 192 seconds for the first 10 retries, leaving 108 seconds left, or 2 more requests (rounding up).
from requests import session from orionclient.utils import Backoff def retry_get_with_backoff(url, attempts=10, request_timeout=10): sess = session() tries = 0 sleeper = Backoff() resp = None while tries < attempts: resp = sess.get(url, timeout=request_timeout) if not resp.ok: tries += 1 sleeper.sleep() continue return resp return resp
Exponential sleep based on the number of tries
- class orionclient.utils.TemporaryPath(suffix='', prefix='tmp', dir=None, delete=True)¶
Provides a temporary file path, suggested usage is as a context manager.
This is safe to use cross-platform where NamedTemporaryFile is not.
with TemporaryPath(suffix="bar") as path: with open(path, "wb") as ofs: ofs.write(b"bytes")