Client

Client is a wrapper for HTTP calls which allows to use load balancers, circuit breakers and retries.

class ahoyhoy.client.Client(lb, ep_list_update_tries=1, **ep_kwargs)[source]

A load balancing, circuit breaking client.

Accepts load balancer instance as an argument. Client can be a duck-typed requests object.

Usage examples:

  1. Client with RoundRobin LB and bad hosts
>>> from ahoyhoy.utils import Host
>>> from ahoyhoy.lb.providers import ListProvider
>>> from ahoyhoy.lb import RoundRobinLB
>>> bad_host1 = Host('google1.com1', '80')
>>> bad_host2 = Host('google2.com2', '80')
>>> good_host = Host('google.com', '80')
>>> rrlb = RoundRobinLB(ListProvider(bad_host1, bad_host2, good_host))
>>> client = Client(rrlb)
>>> client.get('/')
<Response [200]>

Note! Client only accepts HTTP calls for now.

Session’s attributes and methods (except HTTP calls) are unavailable for calls through the Client’s instance. Because of the dynamic nature of Endpoint s, all parameters (such as headers etc.) have to be changed through the client-specific API.

Consider these examples:

>>> client.headers.update({'bla': 'foo'})
Traceback (most recent call last):
...
AttributeError: No such attribute: 'headers'. Only HTTP methods can be called for now.
>>> c = Client(rrlb, headers={'bla': 'foo'})
>>> response = c.get('/')
>>> assert 'bla' in response.request.headers.keys()
Parameters:
  • lb – instance of ILoadBalancer
  • ep_list_update_tries – how many times to try to update endpoints list in LB
  • ep_kwargs – arguments to pass to an Endpoint (‘retry_http_call_func’, ‘headers’)
resolve()[source]

Resolve an Endpoint. If NoAvailableEndpointsLbException was raised, it’s possible to add more “tries”, update Endpoints list and try to resolve it one more time. (see ._resolve)

ahoyhoy.client.SimpleClient(session=None, retry_http_call=None)[source]

Shortcut

>>> from ahoyhoy.client.client import SimpleClient
>>> client = SimpleClient().get('http://google.com')

Client Builders

ClientBuilder provides convenient api for creating the specific Client instance.

Abstract class:

class ahoyhoy.client.builder.IClientBuilder[source]

Abstract Builder class. Contains required methods for all other client builders.

add_headers(headers)[source]

Provide your custom headers here.

add_retries(retries)[source]

Custom retries function. It has to accept function to retry w/ its args and kwargs. It’s highly recommended to use ahoyhoy.retries.Retry() function with custom parameters.

add_session(session)[source]

Add your custom session here.

build()[source]

Build and return the client.

class ahoyhoy.client.LBClientBuilder[source]

Bases: ahoyhoy.client.builder.IClientBuilder

Usage examples:

  1. Round Robin LB

    >>> from ahoyhoy.utils import Host
    >>> from ahoyhoy.lb.providers import ListProvider
    >>> from ahoyhoy.lb import RoundRobinLB
    >>>
    >>> rrlb = RoundRobinLB(ListProvider(Host('badhost2.bla', 80), Host('google.com', 80), Host('badhost3.bla', 80)))
    >>>
    >>> client = LBClientBuilder().add_lb(rrlb).build()
    >>> client.get('/')
    <Response [200]>
    
  2. Round Robin LB and custom session

    >>> import requests
    >>> s = requests.Session()
    >>> s.headers.update({'bla': 'foo'})
    >>> client = LBClientBuilder().add_lb(rrlb).add_session(s).build()
    >>> client.get('/')
    <Response [200]>
    
  3. Round Robin LB with custom HTTP retries

    >>> from ahoyhoy.retries import Retry
    >>> from requests.exceptions import ConnectTimeout
    >>>
    >>> retries = Retry(exceptions=ConnectTimeout, tries=3, delay=0, max_delay=None, backoff=2, jitter=0)
    >>> rrlb = RoundRobinLB(ListProvider(Host('google.com', 80)))
    >>>
    >>> client = LBClientBuilder().add_lb(rrlb).add_retries(retries).build()
    >>> client.get('/')
    <Response [200]>
    
  4. Set multiple updates for endpoints list

    >>> client = LBClientBuilder().add_lb(rrlb).set_endpoint_updates(3)
    
add_lb(lb)[source]

Add your load balancer instance here.

set_endpoint_updates(ep_updates)[source]

Sets the number of times an endpoints list has to be updated. By default it’s 1, which is the initial update of available endpoints.

Parameters:ep_updates – int, number of updates of ep list if there’re no endpoints in the closed state
class ahoyhoy.client.SessionClientBuilder[source]

Bases: ahoyhoy.client.builder.IClientBuilder

Usage example:

>>> import requests
>>> from ahoyhoy.client.builder import SessionClientBuilder
>>>
>>> s = requests.Session()
>>>
>>> client = SessionClientBuilder().add_session(s).build()
>>> client.get('http://google.com')
<Response [200]>

Custom headers:

>>> s.headers.update({'bla': 'foo'})
>>> client = SessionClientBuilder().add_session(s).build()
>>> response = client.get('http://google.com')
>>> assert 'bla' in response.request.headers

or

>>> client = SessionClientBuilder().add_session(s).add_headers({'foo': 'bar'}).build()
>>> response = client.get('http://google.com')
>>> assert 'foo' in response.request.headers

Custom retries:

>>> from ahoyhoy.retries import Retry
>>> from requests.exceptions import ConnectTimeout
>>>
>>> retries = Retry(exceptions=ConnectTimeout, tries=3, delay=0, max_delay=None, backoff=2, jitter=0)
>>>
>>> client = SessionClientBuilder().add_session(s).add_retries(retries).build()
>>> client.get('http://google.com')
<Response [200]>

Client exceptions

class ahoyhoy.client.exceptions.NoAvailableEndpointsClientException[source]

No Endpoints in the closed state, even after lists updates.

class ahoyhoy.client.exceptions.AhoyhoyRequestsException(*args, **kwargs)[source]

Request failed for any reason

Initialize RequestException with request and response objects.