mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-31 07:26:44 +00:00
request/nonce: Refactor to simplify package and prevent consecutive mutex lock calls when accessing/setting nonce values (#1506)
* improv. timed mutex * Add all protection back in and jankyness because races. :'( * Add intial benchmarkeroos * Add master benchmarks * goodness me * what? * what again? * glorious: nits * just a swaperino instead * clean up package nonce so that we only need to aquire mutex once * unlock before checking master * commentary * wha * more comment * ch comment * nonce: Allow for broad customisation externally with a ~2ns overhead * glorious: nits maybe works? --------- Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
This commit is contained in:
@@ -226,11 +226,7 @@ func (r *Requester) doRequest(ctx context.Context, endpoint EndpointLimit, newRe
|
||||
}
|
||||
|
||||
if verbose {
|
||||
log.Errorf(log.RequestSys,
|
||||
"%s request has failed. Retrying request in %s, attempt %d",
|
||||
r.name,
|
||||
delay,
|
||||
attempt)
|
||||
log.Errorf(log.RequestSys, "%s request has failed. Retrying request in %s, attempt %d", r.name, delay, attempt)
|
||||
}
|
||||
|
||||
time.Sleep(delay)
|
||||
@@ -281,21 +277,12 @@ func (r *Requester) doRequest(ctx context.Context, endpoint EndpointLimit, newRe
|
||||
|
||||
err = resp.Body.Close()
|
||||
if err != nil {
|
||||
log.Errorf(log.RequestSys,
|
||||
"%s failed to close request body %s",
|
||||
r.name,
|
||||
err)
|
||||
log.Errorf(log.RequestSys, "%s failed to close request body %s", r.name, err)
|
||||
}
|
||||
if verbose {
|
||||
log.Debugf(log.RequestSys,
|
||||
"HTTP status: %s, Code: %v",
|
||||
resp.Status,
|
||||
resp.StatusCode)
|
||||
log.Debugf(log.RequestSys, "HTTP status: %s, Code: %v", resp.Status, resp.StatusCode)
|
||||
if !p.HTTPDebugging {
|
||||
log.Debugf(log.RequestSys,
|
||||
"%s raw response: %s",
|
||||
r.name,
|
||||
string(contents))
|
||||
log.Debugf(log.RequestSys, "%s raw response: %s", r.name, string(contents))
|
||||
}
|
||||
}
|
||||
return unmarshallError
|
||||
@@ -304,44 +291,19 @@ func (r *Requester) doRequest(ctx context.Context, endpoint EndpointLimit, newRe
|
||||
|
||||
func (r *Requester) drainBody(body io.ReadCloser) {
|
||||
if _, err := io.Copy(io.Discard, io.LimitReader(body, drainBodyLimit)); err != nil {
|
||||
log.Errorf(log.RequestSys,
|
||||
"%s failed to drain request body %s",
|
||||
r.name,
|
||||
err)
|
||||
log.Errorf(log.RequestSys, "%s failed to drain request body %s", r.name, err)
|
||||
}
|
||||
|
||||
if err := body.Close(); err != nil {
|
||||
log.Errorf(log.RequestSys,
|
||||
"%s failed to close request body %s",
|
||||
r.name,
|
||||
err)
|
||||
log.Errorf(log.RequestSys, "%s failed to close request body %s", r.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetNonce returns a nonce for requests. This locks and enforces concurrent
|
||||
// nonce FIFO on the buffered job channel
|
||||
func (r *Requester) GetNonce(isNano bool) nonce.Value {
|
||||
func (r *Requester) GetNonce(set nonce.Setter) nonce.Value {
|
||||
r.timedLock.LockForDuration()
|
||||
if r.Nonce.Get() == 0 {
|
||||
if isNano {
|
||||
r.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
r.Nonce.Set(time.Now().Unix())
|
||||
}
|
||||
return r.Nonce.Get()
|
||||
}
|
||||
return r.Nonce.GetInc()
|
||||
}
|
||||
|
||||
// GetNonceMilli returns a nonce for requests. This locks and enforces concurrent
|
||||
// nonce FIFO on the buffered job channel this is for millisecond
|
||||
func (r *Requester) GetNonceMilli() nonce.Value {
|
||||
r.timedLock.LockForDuration()
|
||||
if r.Nonce.Get() == 0 {
|
||||
r.Nonce.Set(time.Now().UnixMilli())
|
||||
return r.Nonce.Get()
|
||||
}
|
||||
return r.Nonce.GetInc()
|
||||
return r.Nonce.GetAndIncrement(set)
|
||||
}
|
||||
|
||||
// SetProxy sets a proxy address for the client transport
|
||||
|
||||
@@ -18,7 +18,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/nonce"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
@@ -494,37 +497,35 @@ func TestDoRequest_NotRetryable(t *testing.T) {
|
||||
|
||||
func TestGetNonce(t *testing.T) {
|
||||
t.Parallel()
|
||||
r, err := New("test",
|
||||
new(http.Client),
|
||||
WithLimiter(&globalshell))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n1, n2 := r.GetNonce(false), r.GetNonce(false); n1 == n2 {
|
||||
t.Fatal(unexpected)
|
||||
}
|
||||
r, err := New("test", new(http.Client), WithLimiter(&globalshell))
|
||||
require.NoError(t, err)
|
||||
n1 := r.GetNonce(nonce.Unix)
|
||||
assert.NotZero(t, n1)
|
||||
n2 := r.GetNonce(nonce.Unix)
|
||||
assert.NotZero(t, n2)
|
||||
assert.NotEqual(t, n1, n2)
|
||||
|
||||
r2, err := New("test",
|
||||
new(http.Client),
|
||||
WithLimiter(&globalshell))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n1, n2 := r2.GetNonce(true), r2.GetNonce(true); n1 == n2 {
|
||||
t.Fatal(unexpected)
|
||||
}
|
||||
r2, err := New("test", new(http.Client), WithLimiter(&globalshell))
|
||||
require.NoError(t, err)
|
||||
n3 := r2.GetNonce(nonce.UnixNano)
|
||||
assert.NotZero(t, n3)
|
||||
n4 := r2.GetNonce(nonce.UnixNano)
|
||||
assert.NotZero(t, n4)
|
||||
assert.NotEqual(t, n3, n4)
|
||||
|
||||
assert.NotEqual(t, n1, n3)
|
||||
assert.NotEqual(t, n2, n4)
|
||||
}
|
||||
|
||||
func TestGetNonceMillis(t *testing.T) {
|
||||
t.Parallel()
|
||||
r, err := New("test",
|
||||
new(http.Client),
|
||||
WithLimiter(&globalshell))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m1, m2 := r.GetNonceMilli(), r.GetNonceMilli(); m1 == m2 {
|
||||
log.Fatal(unexpected)
|
||||
// 40532461 30.29 ns/op 0 B/op 0 allocs/op (prev)
|
||||
// 45329203 26.53 ns/op 0 B/op 0 allocs/op
|
||||
func BenchmarkGetNonce(b *testing.B) {
|
||||
r, err := New("test", new(http.Client), WithLimiter(&globalshell))
|
||||
require.NoError(b, err)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.GetNonce(nonce.UnixNano)
|
||||
r.timedLock.UnlockIfLocked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user