Documentation
¶
Overview ¶
Package httpclient wraps net/http with retry, circuit breaker, and tracing so consumers stop reimplementing the same outbound-call boilerplate.
c := httpclient.New(
httpclient.WithBaseURL("https://api.example.com"),
httpclient.WithTimeout(5 * time.Second),
httpclient.WithRetries(3),
httpclient.WithBreaker(httpclient.NewBreaker()),
)
res, err := c.Do(ctx, req)
Index ¶
- Variables
- func FxModule(name string, opts ...Option) fx.Option
- func IsRetriable(err error) bool
- func NewObservabilityTransport(base http.RoundTripper, log logger.Logger, tr tracer.Tracer) http.RoundTripper
- type Breaker
- type BreakerOption
- type Client
- type Option
- func WithBackoff(opts ...retry.Option) Option
- func WithBaseURL(url string) Option
- func WithBreaker(b *Breaker) Option
- func WithBreakerPerHost(threshold int, cooldown time.Duration) Option
- func WithHTTPClient(c *http.Client) Option
- func WithHeaders(fn func() http.Header) Option
- func WithRetries(n int) Option
- func WithRetryAll() Option
- func WithTimeout(d time.Duration) Option
- func WithTransport(rt http.RoundTripper) Option
- type PerHostBreaker
- type State
Constants ¶
This section is empty.
Variables ¶
var ErrBreakerOpen = errors.New("httpclient: circuit breaker open")
ErrBreakerOpen is returned by the client when the circuit is open.
Functions ¶
func FxModule ¶ added in v0.3.0
FxModule registers a named *Client in the fx graph so a service can hold several clients (one per upstream) and inject the right one by name.
Usage:
app.Run(
app.WithName("billing"),
httpclient.FxModule("stripe",
httpclient.WithBaseURL("https://api.stripe.com"),
httpclient.WithRetries(3),
httpclient.WithBreakerPerHost(5, 30*time.Second)),
httpclient.FxModule("slack",
httpclient.WithBaseURL("https://slack.com/api")),
internal.FxModule(),
)
// Inject by name:
type StripeDeps struct {
fx.In
Client *httpclient.Client `name:"stripe"`
}
The module name doubles as the fx group key so duplicate registrations panic at boot.
func IsRetriable ¶
IsRetriable reports whether an error is one the client retried on.
func NewObservabilityTransport ¶ added in v0.3.0
func NewObservabilityTransport(base http.RoundTripper, log logger.Logger, tr tracer.Tracer) http.RoundTripper
NewObservabilityTransport wraps base so every outbound request gets an OTel span (propagated via W3C tracecontext headers) and a single structured log line on completion with method / host / status / duration. Pass it to WithTransport, or rely on FxModule to wire it automatically when logger + tracer are available in the fx graph.
Types ¶
type Breaker ¶
type Breaker struct {
// contains filtered or unexported fields
}
Breaker is a small failure-rate-based circuit breaker.
func NewBreaker ¶
func NewBreaker(opts ...BreakerOption) *Breaker
NewBreaker constructs a breaker. Defaults: threshold 5, cooldown 30s.
func (*Breaker) RecordFailure ¶
func (b *Breaker) RecordFailure()
RecordFailure increments the consecutive-failure counter and trips the breaker once it reaches the threshold.
type BreakerOption ¶
type BreakerOption func(*Breaker)
func WithCooldown ¶
func WithCooldown(d time.Duration) BreakerOption
func WithThreshold ¶
func WithThreshold(n int) BreakerOption
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an http.Client wrapper with retry + breaker + per-attempt timeout.
type Option ¶
type Option func(*Client)
func WithBackoff ¶
WithBackoff overrides the retry policy options. Defaults to exponential backoff starting at 100ms.
func WithBaseURL ¶
WithBaseURL prepends a base URL to relative request paths.
func WithBreaker ¶
WithBreaker installs a circuit breaker. When the breaker is open, Do returns ErrBreakerOpen immediately without contacting the server.
func WithBreakerPerHost ¶ added in v0.3.0
WithBreakerPerHost installs a manager that builds a separate *Breaker per upstream host. One bad downstream stops poisoning unrelated calls. Mutually exclusive with WithBreaker; the per-host manager wins if both are supplied.
func WithHTTPClient ¶
WithHTTPClient overrides the underlying http.Client. Useful when callers want shared connection pooling. Resets timeout to the supplied client's.
func WithHeaders ¶
WithHeaders installs a header factory invoked per attempt. Headers from the inbound request are preserved; factory headers are added on top (typical use: Authorization, X-Tenant-ID).
func WithRetries ¶
WithRetries sets the total number of attempts (1 = no retry, default 1).
func WithRetryAll ¶ added in v0.3.0
func WithRetryAll() Option
WithRetryAll opts every HTTP method into the retry policy. By default retries are gated to idempotent methods (GET, HEAD, PUT, DELETE, OPTIONS) per RFC 9110 §9.2.2 — replaying POST/PATCH can double-charge / double-create. Use this for endpoints you know are idempotent on the server side despite the verb.
func WithTimeout ¶
WithTimeout sets the per-attempt timeout. The http.Client's own timeout is left alone; this wraps the request context.
func WithTransport ¶
func WithTransport(rt http.RoundTripper) Option
WithTransport overrides the RoundTripper. Combine with NewTracingTransport from go/kit/transport/rest for OTEL spans.
type PerHostBreaker ¶ added in v0.3.0
type PerHostBreaker struct {
// contains filtered or unexported fields
}
PerHostBreaker keeps a separate *Breaker per upstream host so one flaky downstream doesn't poison unrelated calls. Breakers are created lazily on first request to a given host.
func NewPerHostBreaker ¶ added in v0.3.0
func NewPerHostBreaker(threshold int, cooldown time.Duration) *PerHostBreaker
NewPerHostBreaker returns a manager that builds per-host breakers using the supplied threshold + cooldown.
func (*PerHostBreaker) For ¶ added in v0.3.0
func (p *PerHostBreaker) For(host string) *Breaker
For returns the breaker for host, creating one on demand.
func (*PerHostBreaker) Snapshot ¶ added in v0.3.0
func (p *PerHostBreaker) Snapshot() map[string]State
Snapshot returns the current per-host breaker state. Useful for /healthz handlers that want to expose breaker status.