Skip to content

Commit

Permalink
Merge branch 'main' into hotfix/broken-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
schmidtw authored Jul 6, 2023
2 parents 1c87183 + 33f76c0 commit b7bf1ee
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 68 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ on:
- MAINTAINERS.md
- LICENSE
- NOTICE
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
pull_request:
workflow_dispatch:

jobs:
ci:
uses: xmidt-org/.github/.github/workflows/go-ci.yml@go-ci-v1
uses: xmidt-org/shared-go/.github/workflows/ci.yml@6dd1fab69f841fbea827a053e21fa83ea94774d9 # v3.0.0
with:
copyright-skip: true
release-type: library
secrets: inherit
34 changes: 17 additions & 17 deletions erraux/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,14 @@ type Encoder struct {
//
// Invoking this method only affects subsequent calls up to the next invocation:
//
// Encoder{}.
// Body(false).
// // these errors will be rendered without a body
// Is(ErrSomething).
// As((*SomeError)(nil).
// Body(true).
// // this error will be rendered with a body
// As((*MyError)(nil)) // this will be rendered with a body
// Encoder{}.
// Body(false).
// // these errors will be rendered without a body
// Is(ErrSomething).
// As((*SomeError)(nil).
// Body(true).
// // this error will be rendered with a body
// As((*MyError)(nil)) // this will be rendered with a body
func (e Encoder) Body(v bool) Encoder {
e.disableBody = !v
return e
Expand All @@ -372,21 +372,21 @@ func (e Encoder) Add(rules ...EncoderRule) Encoder {
// status code, and will be the same as what was passed to WriteHeader. The cause field is
// the value of Error(). For example:
//
// {"code": 404, "cause": "resource not found"}
// {"code": 500, "cause": "parsing error"}
// {"code": 404, "cause": "resource not found"}
// {"code": 500, "cause": "parsing error"}
//
// Beyond that, errors may implement StatusCoder, Headerer, and ErrorFielder
// to tailor the HTTP representation. Any status code set on the rules will override any
// value the error supplies. For example:
//
// type MyError struct{}
// func (e *MyError) StatusCode() int { return 504 }
// func (e *MyError) Error() string { "my error" }
// type MyError struct{}
// func (e *MyError) StatusCode() int { return 504 }
// func (e *MyError) Error() string { "my error" }
//
// // this will override MyError.StatusCode
// e := erraux.Encoder{}.Add(
// erraux.As((*MyError)(nil)).StatusCode(500),
// )
// // this will override MyError.StatusCode
// e := erraux.Encoder{}.Add(
// erraux.As((*MyError)(nil)).StatusCode(500),
// )
//
// By contrast, an headers or fields set on the rule will be appended to whatever the
// error defines at runtime.
Expand Down
2 changes: 1 addition & 1 deletion httpmock/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func BodyString(b string) *BodyReadCloser {
// Bodyf produces a body with fmt.Sprintf. This function is
// equivalent to:
//
// BodyString(fmt.Sprintf(format, args...))
// BodyString(fmt.Sprintf(format, args...))
func Bodyf(format string, args ...interface{}) *BodyReadCloser {
return BodyString(
fmt.Sprintf(format, args...),
Expand Down
3 changes: 2 additions & 1 deletion httpmock/requestChecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ type BodyJSON string
//
// (1) The request body is nil AND this expected JSON is an empty string
// (2) The request body is not nil AND it matches this expected JSON. The
// match is done via stretchr/testify/assert.JSONEq.
//
// match is done via stretchr/testify/assert.JSONEq.
func (b BodyJSON) Assert(assert *assert.Assertions, r *http.Request) {
if r.Body == nil {
// if the body is nil, the only possible match is an empty string
Expand Down
8 changes: 4 additions & 4 deletions retry/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ type Check func(*http.Response, error) bool
// This default implementation returns true under the following conditions:
//
// - The response is not nil and the status code is one of:
// http.StatusRequestTimeout
// http.StatusTooManyRequests
// http.StatusGatewayTimeout
// http.StatusRequestTimeout
// http.StatusTooManyRequests
// http.StatusGatewayTimeout
// - The error is not nil and:
// supplies a "Temporary() bool" method that returns true (including any wrapped errors)
// supplies a "Temporary() bool" method that returns true (including any wrapped errors)
//
// A consequence of honoring the Temporary() method on errors is that transient network errors
// will be retried. Examples of this include DNS errors that are marked as temporary.
Expand Down
26 changes: 13 additions & 13 deletions retry/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@ Package retry implements retry logic for HTTP clients.
The Client type can be used directly and instantiated with New.
client := New(Config{
Retries: 2,
Interval: 10 * time.Second,
}, nil) // uses http.DefaultClient
client := New(Config{
Retries: 2,
Interval: 10 * time.Second,
}, nil) // uses http.DefaultClient
A Client can also be used as client middleware via its Then method.
client := New(Config{})
decorated := client.Then(new(http.Client))
client := New(Config{})
decorated := client.Then(new(http.Client))
Exponential backoff with jitter is also supported. For example:
client := New(Config{
Retries: 2,
Interval: 10 * time.Second,
Multiplier: 2.0,
Jitter: 0.2,
})
client := New(Config{
Retries: 2,
Interval: 10 * time.Second,
Multiplier: 2.0,
Jitter: 0.2,
})
The basic formula for each time to wait before the next retry, in terms of Config fields, is:
Interval * (Multiplier^n) * randBetween[1-Jitter,1+Jitter]
Interval * (Multiplier^n) * randBetween[1-Jitter,1+Jitter]
where n is the 0-based retry.
Expand Down
62 changes: 31 additions & 31 deletions roundtrip/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Package roundtrip provides middleware and a few utility types for use with
http.RoundTripper
Middleware
# Middleware
The Constructor and Chain types provide a way for application code to decorate
an http.RoundTripper, usually an http.Transport, to any arbitrary depth. These
Expand All @@ -11,50 +11,50 @@ types are analogous to https://pkg.go.dev/github.com/justinas/alice.
This package provide the Func type as an analog to http.HandlerFunc. When implementing
middleware, chaining function calls through Func works as with serverside middleware.
CloseIdleConnections
# CloseIdleConnections
When decorating http.RoundTripper, care should be take to avoid covering up the
CloseIdleConnections method. This method is used by the enclosing http.Client.
If middleware does not properly expose CloseIdleConnections, then there is no way
to invoke this method through the client:
// CloseIdleConnections is lost in decoration
func MyConstructor(next http.RoundTripper) http.RoundTripper {
return roundtrip.Func(func(request *http.Request) (*http.Response, error) {
// some interesting decorator code here
return next.RoundTrip(request)
})
}
// CloseIdleConnections is lost in decoration
func MyConstructor(next http.RoundTripper) http.RoundTripper {
return roundtrip.Func(func(request *http.Request) (*http.Response, error) {
// some interesting decorator code here
return next.RoundTrip(request)
})
}
To assist with this, PreserveCloseIdler is provided to ensure that Constructor code
properly exposes a CloseIdleConnections method:
// CloseIdleConnections is now available on the returned http.RoundTripper
func MyConstructor(next http.RoundTripper) http.RoundTripper {
return roundtrip.PreserveCloseIdler(
next,
roundtrip.Func(func(request *http.Request) (*http.Response, error) {
// some interesting decorator code here
return next.RoundTrip(request)
}),
)
}
// CloseIdleConnections is now available on the returned http.RoundTripper
func MyConstructor(next http.RoundTripper) http.RoundTripper {
return roundtrip.PreserveCloseIdler(
next,
roundtrip.Func(func(request *http.Request) (*http.Response, error) {
// some interesting decorator code here
return next.RoundTrip(request)
}),
)
}
If a constructor wants to decorate both the RoundTrip and CloseIdleConnections methods,
the Decorator type and CloseIdleConnections function in this package can be used to facilitate this:
func MyConstructor(next http.RoundTripper) http.RoundTripper {
return roundtrip.Decorator{
RoundTrip: roundTrip.Func(func(request *http.Request) (*http.Response, error) {
// some interesting decorator code here
return next.RoundTrip(request)
}),
CloseIdler: roundtrip.CloseIdlerFunc(func() {
// do some decorator things here
roundtrip.CloseIdleConnections(next)
}),
}
}
func MyConstructor(next http.RoundTripper) http.RoundTripper {
return roundtrip.Decorator{
RoundTrip: roundTrip.Func(func(request *http.Request) (*http.Response, error) {
// some interesting decorator code here
return next.RoundTrip(request)
}),
CloseIdler: roundtrip.CloseIdlerFunc(func() {
// do some decorator things here
roundtrip.CloseIdleConnections(next)
}),
}
}
The Chain type exposes CloseIdleConnections even if any chained constructors do not.
Expand Down

0 comments on commit b7bf1ee

Please sign in to comment.