33 lines
3.2 KiB
Markdown
33 lines
3.2 KiB
Markdown
|
|
# Changelog
|
||
|
|
|
||
|
|
All notable changes to this module will be documented in this file.
|
||
|
|
|
||
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||
|
|
and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||
|
|
|
||
|
|
## [0.9.0] - 2026-03-18
|
||
|
|
|
||
|
|
### Added
|
||
|
|
|
||
|
|
- `Client` interface: `Do(req *http.Request) (*http.Response, error)`.
|
||
|
|
- `Config` struct: fields `Name`, `Timeout` (default `30s`), `DialTimeout` (default `5s`), `MaxRetries` (default `3`), `RetryDelay` (default `1s`), `CBThreshold` (default `10`), `CBTimeout` (default `1m`); settable via `HTTP_*` environment variables.
|
||
|
|
- `DefaultConfig() Config`: returns a `Config` populated with all default values.
|
||
|
|
- `New(logger logz.Logger, cfg Config) Client`: constructs a client with a `gobreaker` circuit breaker wrapping an `avast/retry-go` retry loop. The circuit breaker trips after `CBThreshold` consecutive failures and resets after `CBTimeout`.
|
||
|
|
- `NewWithDefaults(logger logz.Logger) Client`: convenience constructor; equivalent to `New(logger, DefaultConfig())`.
|
||
|
|
- Retry behaviour: up to `MaxRetries` attempts with exponential backoff (`retry.BackOffDelay`). Only network errors and HTTP 5xx responses are retried; 4xx responses are not.
|
||
|
|
- Circuit breaker behaviour: the breaker wraps the full retry sequence, so one fully-exhausted retry sequence counts as one failure. State transitions are logged at `Warn` level with `name`, `from`, and `to` fields.
|
||
|
|
- Request ID propagation: `logz.GetRequestID(ctx)` is called on each attempt; if a request ID is present, it is forwarded as the `X-Request-ID` request header.
|
||
|
|
- Per-request structured logging: successful requests emit an `Info` log with `method`, `url`, `status`, and `latency` fields; failed individual attempts emit a `Debug` log.
|
||
|
|
- Error mapping on `Do`: open circuit → `ErrUnavailable`; post-retry HTTP error response → `MapStatusToError`; network/timeout error → `ErrInternal`.
|
||
|
|
- `DoJSON[T any](ctx context.Context, client Client, req *http.Request) (*T, error)`: generic free function that executes a request and decodes the JSON response body into `T`; returns `*T` on success and a xerrors-typed error for network failures, HTTP 4xx/5xx responses, unreadable bodies, or JSON decode failures.
|
||
|
|
- `MapStatusToError(code int, msg string) error` (exported): maps HTTP status codes to xerrors codes — `404` → `ErrNotFound`, `400` → `ErrInvalidInput`, `401` → `ErrUnauthorized`, `403` → `ErrPermissionDenied`, `409` → `ErrAlreadyExists`, `429` → `ErrUnavailable`, all others → `ErrInternal`.
|
||
|
|
- Dial timeout applied via a custom `net.Dialer` on the `http.Transport`, independent of the per-request `Timeout`.
|
||
|
|
|
||
|
|
### Design Notes
|
||
|
|
|
||
|
|
- The circuit breaker wraps the retry loop rather than individual attempts; a full set of exhausted retries registers as a single failure against the breaker threshold, preventing overly aggressive tripping.
|
||
|
|
- `DoJSON` is a free generic function rather than a method so it works with any `Client` implementation, including mocks, without requiring a concrete type.
|
||
|
|
- The module has no lifecycle (no `OnInit`/`OnStart`/`OnStop`) and does not depend on `launcher` or `health`; it is a stateless constructor suitable for use at any tier.
|
||
|
|
|
||
|
|
[0.9.0]: https://code.nochebuena.dev/go/httpclient/releases/tag/v0.9.0
|