HTTP Support
- Clients
- Servers
- Retrying HTTP Failures
- Handling Retry-After
- Propagating Priorities
- Context Cancellation
Failsafe-go makes it easy to use any policies with HTTP.
Clients
You can create a failsafe RoundTripper
for a policy composition which can be used with an http.Client
:
client := &http.Client{
Transport: failsafehttp.NewRoundTripper(http.DefaultTransport, retryPolicy, circuitBreaker),
}
// Get with retries and circuit breaking
client.Get("http://failsafe-go.dev")
Alternatively, you can create a failsafe request for an http.Request
, http.Client
, and policies:
failsafeRequest := failsafehttp.NewRequest(request, client, retryPolicy)
// Perform request with retries
response, err := failsafeRequest.Do()
The difference between these two approaches is that a failsafe Request
wraps a client whereas a failsafe RoundTripper
is used internally by a client. This means any errors created by a client before using the RoundTripper
would not be handled, but could be handled by a failsafe Request
.
Servers
On the server side, you can use load limiting or time limiting policies to create a failsafe http.Handler
:
handler = failsafehttp.NewHandler(innerHandler, bulkhead, timeout)
Retrying HTTP Failures
The failsafehttp
package provides a NewRetryPolicyBuilder
that can build retry policies with built-in detection of retryable HTTP errors and responses:
retryPolicy := failsafehttp.NewRetryPolicyBuilder().
WithBackoff(time.Second, 30*time.Second).
WithMaxRetries(3).
Build()
failsafehttp.NewRetryPolicyBuilder
will also delay retries according to any Retry-After
header in the HTTP response. Additional configuration, including delays for other responses, can be added to the builder as needed.
Handling Retry-After
Other policies that support delays, such as circuit breakers can also be configured with a failsafehttp.DelayFunc
that delays according to Retry-After
headers:
circuitBreaker := circuitbreaker.NewBuilder[*http.Response]().
HandleIf(func(response *http.Response, err error) bool {
return response != nil && response.StatusCode == 429
}).
WithDelayFunc(failsafehttp.DelayFunc).
Build()
Propagating Priorities
When using policies that support execution prioritization, ideally priorities and levels should be propagated from HTTP clients to servers, and on to the server’s handler. On the client, we can propagate priority or level information from a context through an outgoing request by using a RoundTripper
:
client := &http.Client{
Transport: failsafehttp.NewRoundTripperWithLevel(nil),
}
And on the server, we can decode priority or level information from an incoming request, optionally generate a level if one does not exist but a priority does, and propagate it to the http.Handler
:
handler := failsafehttp.NewHandlerWithLevel(innerHandler, true)
For distributed systems, you typically want to generate a level, if one does not exist, at the edge of your system, and then propagate the same level for all sub-requests.
Context Cancellation
When using a failsafe RoundTripper
or Request
, Context cancellations are automatically propagated to the HTTP request context. When an execution is canceled for any reason, such as a Timeout, any outstanding HTTP request’s context is canceled. Similarly, when using a HedgePolicy, any outstanding hedge reqests contexts are canceled once the first successful response is received.