1
// Copyright 2013 Canonical Ltd. This software is licensed under the
2
// GNU Lesser General Public License version 3 (see the file COPYING).
7
forkedHttp "launchpad.net/gwacl/fork/http"
12
// A RetryPolicy object encapsulates all the information needed to define how
13
// requests should be retried when particular response codes are returned by
14
// the Windows Azure server.
15
type RetryPolicy struct {
16
// The number of times a request could be retried. This does not account
17
// for the initial request so a value of 3 means that the request might be
18
// performed 4 times in total.
20
// The HTTP status codes of the response for which the request should be
23
// How long the client should wait between retries.
28
NoRetryPolicy = RetryPolicy{NbRetries: 0}
31
// isRetryCode returns whether or not the given http status code indicates that
32
// the request should be retried according to this policy.
33
func (policy RetryPolicy) isRetryCode(httpStatusCode int) bool {
34
for _, code := range policy.HttpStatusCodes {
35
if code == httpStatusCode {
42
func (policy RetryPolicy) getRetryHelper() *retryHelper {
43
return &retryHelper{retriesLeft: policy.NbRetries, policy: &policy}
46
// A retryHelper is a utility object used to enforce a retry policy when
47
// performing requests.
48
type retryHelper struct {
49
// The maximum number of retries left to perform.
51
// The `RetryPolicy` enforced by this retrier.
55
// shouldRetry returns whether or not a request governed by the underlying
56
// retry policy should be retried. When it returns 'true', `shouldRetry` also
57
// waits for the specified amount of time, as dictated by the retry policy.
58
func (ret *retryHelper) shouldRetry(httpStatusCode int) bool {
59
if ret.retriesLeft > 0 && ret.policy.isRetryCode(httpStatusCode) {
66
// A retrier is a struct used to repeat a request as governed by a retry
67
// policy. retrier is usually created using RetryPolicy.getRetrier().
71
// The client used to perform requests.
75
func (ret *retrier) RetryRequest(request *http.Request) (*http.Response, error) {
77
response, err := ret.client.Do(request)
81
if !ret.shouldRetry(response.StatusCode) {
84
time.Sleep(ret.policy.Delay)
88
// getRetrier returns a `retrier` object used to enforce the retry policy.
89
func (policy RetryPolicy) getRetrier(client *http.Client) *retrier {
90
helper := policy.getRetryHelper()
91
return &retrier{retryHelper: helper, client: client}
94
// A forkedHttpRetrier is a struct used to repeat a request as governed by a
95
// retry policy. forkedHttpRetrier is usually created using
96
// RetryPolicy.getForkedHttpRetrier(). It's the same as the `retrier` struct
97
// except it deals with the forked version of the http package.
98
type forkedHttpRetrier struct {
101
// The client used to perform requests.
102
client *forkedHttp.Client
105
func (ret *forkedHttpRetrier) RetryRequest(request *forkedHttp.Request) (*forkedHttp.Response, error) {
107
response, err := ret.client.Do(request)
111
if !ret.shouldRetry(response.StatusCode) {
114
time.Sleep(ret.policy.Delay)
118
// getRetrier returns a `retrier` object used to enforce the retry policy.
119
func (policy RetryPolicy) getForkedHttpRetrier(client *forkedHttp.Client) *forkedHttpRetrier {
120
helper := policy.getRetryHelper()
121
return &forkedHttpRetrier{retryHelper: helper, client: client}