@ -148,8 +148,11 @@ func NewWriteClient(name string, conf *ClientConfig) (WriteClient, error) {
} , nil
}
const defaultBackoff = 0
type RecoverableError struct {
error
retryAfter model . Duration
}
// Store sends a batch of samples to the HTTP endpoint, the request is the proto marshalled
@ -188,7 +191,7 @@ func (c *Client) Store(ctx context.Context, req []byte) error {
if err != nil {
// Errors from Client.Do are from (for example) network errors, so are
// recoverable.
return RecoverableError { err }
return RecoverableError { err , defaultBackoff }
}
defer func ( ) {
io . Copy ( ioutil . Discard , httpResp . Body )
@ -204,11 +207,30 @@ func (c *Client) Store(ctx context.Context, req []byte) error {
err = errors . Errorf ( "server returned HTTP status %s: %s" , httpResp . Status , line )
}
if httpResp . StatusCode / 100 == 5 {
return RecoverableError { err }
return RecoverableError { err , defaultBackoff }
}
if httpResp . StatusCode == http . StatusTooManyRequests {
return RecoverableError { err , retryAfterDuration ( httpResp . Header . Get ( "Retry-After" ) ) }
}
return err
}
// retryAfterDuration returns the duration for the Retry-After header. In case of any errors, it
// returns the defaultBackoff as if the header was never supplied.
func retryAfterDuration ( t string ) model . Duration {
parsedDuration , err := time . Parse ( http . TimeFormat , t )
if err == nil {
s := time . Until ( parsedDuration ) . Seconds ( )
return model . Duration ( s ) * model . Duration ( time . Second )
}
// The duration can be in seconds.
d , err := strconv . Atoi ( t )
if err != nil {
return defaultBackoff
}
return model . Duration ( d ) * model . Duration ( time . Second )
}
// Name uniquely identifies the client.
func ( c Client ) Name ( ) string {
return c . remoteName