mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
add exponential backoff for network errors in corrosion client
This commit is contained in:
@@ -6,6 +6,7 @@ toolchain go1.22.5
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/charmbracelet/huh v0.6.0
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5
|
||||
@@ -28,6 +29,7 @@ require (
|
||||
go.uber.org/zap v1.27.0
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.27.0
|
||||
golang.org/x/net v0.29.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/sys v0.25.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
@@ -48,7 +50,6 @@ require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.2.0 // indirect
|
||||
github.com/catppuccin/go v0.2.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/bubbles v0.20.0 // indirect
|
||||
@@ -163,7 +164,6 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.25.0 // indirect
|
||||
|
||||
@@ -7,8 +7,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"golang.org/x/net/http2"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
@@ -20,7 +22,7 @@ const (
|
||||
// HTTP2ConnectTimeout is the maximum amount of time a client will wait for a connection to be established.
|
||||
http2ConnectTimeout = 3 * time.Second
|
||||
// HTTP2Timeout is the maximum amount of time a client will wait for a response.
|
||||
http2Timeout = 30 * time.Second
|
||||
http2Timeout = 20 * time.Second
|
||||
)
|
||||
|
||||
// APIClient is a client for the Corrosion API.
|
||||
@@ -38,7 +40,8 @@ func NewAPIClient(addr netip.AddrPort) (*APIClient, error) {
|
||||
baseURL: baseURL,
|
||||
client: &http.Client{
|
||||
Timeout: http2Timeout,
|
||||
Transport: &http2.Transport{
|
||||
Transport: &RetryRoundTripper{
|
||||
Base: &http2.Transport{
|
||||
AllowHTTP: true,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
|
||||
dialer := &net.Dialer{
|
||||
@@ -47,10 +50,41 @@ func NewAPIClient(addr netip.AddrPort) (*APIClient, error) {
|
||||
return dialer.DialContext(ctx, network, addr)
|
||||
},
|
||||
},
|
||||
Backoff: backoff.NewExponentialBackOff(
|
||||
backoff.WithInitialInterval(100*time.Millisecond),
|
||||
backoff.WithMaxInterval(1*time.Second),
|
||||
backoff.WithMaxElapsedTime(10*time.Second),
|
||||
),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type RetryRoundTripper struct {
|
||||
Base http.RoundTripper
|
||||
Backoff backoff.BackOff
|
||||
}
|
||||
|
||||
func (rt *RetryRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
roundTrip := func() (*http.Response, error) {
|
||||
resp, err := rt.Base.RoundTrip(req)
|
||||
if err != nil {
|
||||
var opErr *net.OpError
|
||||
if errors.As(err, &opErr) {
|
||||
// Not certain, but I expect operational errors should generally be retryable.
|
||||
slog.Debug("Retrying corrosion API request due to network error", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
// Don't retry on other errors.
|
||||
return nil, backoff.Permanent(err)
|
||||
}
|
||||
// Success, don't retry.
|
||||
return resp, err
|
||||
}
|
||||
boff := backoff.WithContext(rt.Backoff, req.Context())
|
||||
return backoff.RetryWithData(roundTrip, boff)
|
||||
}
|
||||
|
||||
type Statement struct {
|
||||
Query string `json:"query"`
|
||||
Params []any `json:"params"`
|
||||
|
||||
Reference in New Issue
Block a user