Merge lp:~leonardr/lazr.restfulclient/retry_on_502 into lp:lazr.restfulclient
Proposed by
Leonard Richardson
Status: | Merged |
---|---|
Approved by: | Brad Crittenden |
Approved revision: | 99 |
Merged at revision: | not available |
Proposed branch: | lp:~leonardr/lazr.restfulclient/retry_on_502 |
Merge into: | lp:lazr.restfulclient |
Diff against target: |
245 lines (+168/-5) 5 files modified
src/lazr/restfulclient/NEWS.txt (+7/-0) src/lazr/restfulclient/_browser.py (+21/-2) src/lazr/restfulclient/docs/retry.standalone.txt (+136/-0) src/lazr/restfulclient/resource.py (+3/-2) src/lazr/restfulclient/version.txt (+1/-1) |
To merge this branch: | bzr merge lp:~leonardr/lazr.restfulclient/retry_on_502 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brad Crittenden (community) | code | Approve | |
Review via email: mp+24257@code.launchpad.net |
Description of the change
This branch changes lazr.restfulclient to retry a request that results in a 502 or 503 error. As bug 380504 demonstrates, these errors are pervasive in the Launchpad web service, but they generally go away immediately. This branch makes scripts based on launchpadlib robust in the face of server-side weirdness.
To post a comment you must log in.
Hi Leonard,
> === modified file 'src/lazr/ restfulclient/ _browser. py' restfulclient/ _browser. py 2010-04-12 19:18:31 +0000 restfulclient/ _browser. py 2010-04-27 19:59:13 +0000
> --- src/lazr/
> +++ src/lazr/
> @@ -242,6 +246,21 @@ root.httpFactor y( and_retry( self, url, method, body, headers): retries+ 1): n.request( (retry_ count-1) )
> self._connection = service_
> credentials, cache, timeout, proxy_info)
> self.user_agent = user_agent
> + self.max_retries = max_retries
> +
> + def _request_
> + for retry_count in range(0, self.max_
> + response, content = self._connectio
> + url, method=method, body=body, headers=headers)
> + if response.status in [502, 503]:
> + # The server returned a 502 or 503. Sleep for 0, 1, 2,
> + # 4, 8, 16, ... seconds and try again.
> + sleep_for = int(2**
> + sleep(sleep_for)
Even after the terminal failure you sleep again. I guess it doesn't
matter but due to the exponential wait times you may have someone
waiting for a long time even though you've given up.
> + else: 'application/ json', extra_headers= None): update( extra_headers) n.request( and_retry(
> + break
> + # Either the request succeeded or we gave up.
> + return response, content
>
> def _request(self, url, data=None, method='GET',
> media_type=
> @@ -261,7 +280,7 @@
> if extra_headers is not None:
> headers.
> # Make the request.
> - response, content = self._connectio
> + response, content = self._request_
> str(url), method=method, body=data, headers=headers)
> if response.status == 304:
> # The resource didn't change.
> === added file 'src/lazr/ restfulclient/ docs/retry. standalone. txt' restfulclient/ docs/retry. standalone. txt 1970-01-01 00:00:00 +0000 restfulclient/ docs/retry. standalone. txt 2010-04-27 19:59:13 +0000 ******* ******* ******* *** resource_ string( tests.data' , 'launchpad- wadl.xml' ) vnd.sun. wadl+xml' : wadl_string,
> --- src/lazr/
> +++ src/lazr/
> @@ -0,0 +1,136 @@
> +Retry requests on server error
> +******
> +
> +If lazr.restfulclient talks to a server that sends out a server-side
> +error with status codes 502 or 503, the client will wait a few seconds
> +and try the request again. Eventually it will give up and escalate the
> +error code in the form of an exception.
> +
> +To test this, let's simulate a lazr.restful server prone to transient
> +errors using a WSGI application.
> +
> + >>> import pkg_resources
> + >>> wadl_string = pkg_resources.
> + ... 'wadllib.
> + >>> representations = { 'application/
> + ... 'application/json' : '{}' }
> +
> +This application will cause one request to fail for every item in its
> +BROKEN_RESPONSES list.
> +
> + >>> class BrokenApplication:
> + ... BROKEN_RESPONSES = []
> + ...
> + ... def __init__(self, environ, start_response):
> + ... self.environ = environ
> + ... self.start_response = start_response
> + ...
> + ... def __iter__(self):
> +...