Skip to content

Commit

Permalink
Replace retry implementation with retry-go
Browse files Browse the repository at this point in the history
  • Loading branch information
0xERR0R committed Dec 13, 2021
1 parent 9b47524 commit 4b85eed
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 56 deletions.
71 changes: 39 additions & 32 deletions lists/list_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"sync"
"time"

"github.com/avast/retry-go"

"github.com/hako/durafmt"

"github.com/hashicorp/go-multierror"
Expand Down Expand Up @@ -230,44 +232,49 @@ func (b *ListCache) downloadFile(link string) (io.ReadCloser, error) {

var resp *http.Response

var err error

logger().WithField("link", link).Info("starting download")

attempt := 1

for attempt <= b.downloadAttempts {
//nolint:bodyclose
if resp, err = client.Get(link); err == nil {
if resp.StatusCode == http.StatusOK {
return resp.Body, nil
}

logger().WithField("link", link).WithField("attempt",
attempt).Warnf("Got status code %d", resp.StatusCode)

_ = resp.Body.Close()

err = fmt.Errorf("couldn't download url '%s', got status code %d", link, resp.StatusCode)
}

var netErr net.Error
var body io.ReadCloser

var dnsErr *net.DNSError
err := retry.Do(
func() error {
var err error
//nolint:bodyclose
if resp, err = client.Get(link); err == nil {
if resp.StatusCode == http.StatusOK {
body = resp.Body
return nil
}

if errors.As(err, &netErr) && (netErr.Timeout() || netErr.Temporary()) {
logger().WithField("link", link).WithField("attempt",
attempt).Warnf("Temporary network err / Timeout occurred, retrying... %s", netErr)
} else if errors.As(err, &dnsErr) {
logger().WithField("link", link).WithField("attempt",
attempt).Warnf("Name resolution err, retrying... %s", dnsErr.Err)
}
_ = resp.Body.Close()

time.Sleep(b.downloadCooldown)
attempt++
}
return fmt.Errorf("got status code %d", resp.StatusCode)
}
return err
},
retry.Attempts(uint(b.downloadAttempts)),
retry.DelayType(retry.FixedDelay),
retry.Delay(b.downloadCooldown),
retry.LastErrorOnly(true),
retry.OnRetry(func(n uint, err error) {
var netErr net.Error

var dnsErr *net.DNSError

logger := logger().WithField("link", link).WithField("attempt",
fmt.Sprintf("%d/%d", n+1, b.downloadAttempts))

switch {
case errors.As(err, &netErr) && (netErr.Timeout() || netErr.Temporary()):
logger.Warnf("Temporary network err / Timeout occurred: %s", netErr)
case errors.As(err, &dnsErr):
logger.Warnf("Name resolution err: %s", dnsErr.Err)
default:
logger.Warnf("Can't download file: %s", err)
}
}))

return nil, err
return body, err
}

func readFile(file string) (io.ReadCloser, error) {
Expand Down
58 changes: 34 additions & 24 deletions resolver/upstream_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"strconv"
"time"

"github.com/avast/retry-go"

"github.com/0xERR0R/blocky/config"
"github.com/0xERR0R/blocky/model"
"github.com/0xERR0R/blocky/util"
Expand Down Expand Up @@ -171,36 +173,44 @@ func (r UpstreamResolver) String() string {

// Resolve calls external resolver
func (r *UpstreamResolver) Resolve(request *model.Request) (response *model.Response, err error) {
logger := withPrefix(request.Log, "upstream_resolver")
const retryAttempts = 3

attempt := 1
logger := withPrefix(request.Log, "upstream_resolver")

var rtt time.Duration

var resp *dns.Msg

for attempt <= 3 {
if resp, rtt, err = r.upstreamClient.callExternal(request.Req, r.upstreamURL, request.Protocol); err == nil {
logger.WithFields(logrus.Fields{
"answer": util.AnswerToString(resp.Answer),
"return_code": dns.RcodeToString[resp.Rcode],
"upstream": r.upstreamURL,
"protocol": request.Protocol,
"net": r.net,
"response_time_ms": rtt.Milliseconds(),
}).Debugf("received response from upstream")

return &model.Response{Res: resp, Reason: fmt.Sprintf("RESOLVED (%s)", r.upstreamURL)}, nil
}

var netErr net.Error
if errors.As(err, &netErr) && (netErr.Timeout() || netErr.Temporary()) {
logger.WithField("attempt", attempt).Debugf("Temporary network error / Timeout occurred, retrying...")
attempt++
} else {
return nil, err
}
err = retry.Do(
func() error {
var err error
if resp, rtt, err = r.upstreamClient.callExternal(request.Req, r.upstreamURL, request.Protocol); err == nil {
logger.WithFields(logrus.Fields{
"answer": util.AnswerToString(resp.Answer),
"return_code": dns.RcodeToString[resp.Rcode],
"upstream": r.upstreamURL,
"protocol": request.Protocol,
"net": r.net,
"response_time_ms": rtt.Milliseconds(),
}).Debugf("received response from upstream")
}
return err
},
retry.Attempts(retryAttempts),
retry.DelayType(retry.FixedDelay),
retry.LastErrorOnly(true),
retry.RetryIf(func(err error) bool {
var netErr net.Error

return errors.As(err, &netErr) && (netErr.Timeout() || netErr.Temporary())
}),
retry.OnRetry(func(n uint, err error) {
logger.WithField("attempt", fmt.Sprintf("%d/%d", n+1, retryAttempts)).
Debugf("Temporary network error / Timeout occurred, retrying...")
}))
if err != nil {
return nil, err
}

return response, err
return &model.Response{Res: resp, Reason: fmt.Sprintf("RESOLVED (%s)", r.upstreamURL)}, nil
}

0 comments on commit 4b85eed

Please sign in to comment.