[chore] transport improvements (#1524)

* improve error readability, mark "bad hosts" as fastFail

Signed-off-by: kim <grufwub@gmail.com>

* pull in latest go-byteutil version with byteutil.Reader{}

Signed-off-by: kim <grufwub@gmail.com>

* use rewindable body reader for post requests

Signed-off-by: kim <grufwub@gmail.com>

---------

Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2023-02-18 16:02:19 +00:00 committed by GitHub
commit a684fc4628
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 84 additions and 63 deletions

View file

@ -32,6 +32,7 @@ import (
"sync"
"time"
"codeberg.org/gruf/go-byteutil"
errorsv2 "codeberg.org/gruf/go-errors/v2"
"codeberg.org/gruf/go-kv"
"github.com/go-fed/httpsig"
@ -84,7 +85,7 @@ type transport struct {
signerMu sync.Mutex
}
// GET will perform given http request using transport client, retrying on certain preset errors, or if status code is among retryOn.
// GET will perform given http request using transport client, retrying on certain preset errors.
func (t *transport) GET(r *http.Request) (*http.Response, error) {
if r.Method != http.MethodGet {
return nil, errors.New("must be GET request")
@ -94,7 +95,7 @@ func (t *transport) GET(r *http.Request) (*http.Response, error) {
})
}
// POST will perform given http request using transport client, retrying on certain preset errors, or if status code is among retryOn.
// POST will perform given http request using transport client, retrying on certain preset errors.
func (t *transport) POST(r *http.Request, body []byte) (*http.Response, error) {
if r.Method != http.MethodPost {
return nil, errors.New("must be POST request")
@ -116,18 +117,17 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error) (*http
// Get request hostname
host := r.URL.Hostname()
// Check if recently reached max retries for this host
// so we don't need to bother reattempting it. The only
// errors that are retried upon are server failure and
// domain resolution type errors, so this cached result
// indicates this server is likely having issues.
if t.controller.badHosts.Has(host) {
return nil, errors.New("too many failed attempts")
}
// Check whether request should fast fail, we check this
// before loop as each context.Value() requires mutex lock.
fastFail := IsFastfail(r.Context())
if !fastFail {
// Check if recently reached max retries for this host
// so we don't bother with a retry-backoff loop. The only
// errors that are retried upon are server failure and
// domain resolution type errors, so this cached result
// indicates this server is likely having issues.
fastFail = t.controller.badHosts.Has(host)
}
// Start a log entry for this request
l := log.WithContext(r.Context()).
@ -148,6 +148,12 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error) (*http
r.Header.Del("Signature")
r.Header.Del("Digest")
// Rewind body reader and content-length if set.
if rc, ok := r.Body.(*byteutil.ReadNopCloser); ok {
r.ContentLength = int64(rc.Len())
rc.Rewind()
}
// Perform request signing
if err := signer(r); err != nil {
return nil, err
@ -226,7 +232,7 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error) (*http
}
}
// Add "bad" entry for this host
// Add "bad" entry for this host.
t.controller.badHosts.Set(host, struct{}{})
return nil, errors.New("transport reached max retries")