Implement Request Retry and Backoff (#491)

Refactoring the timeout retries into a more general 'retry policy' with
 support for retrying on HTTP 429 (Too Many Requests) and other responses
 with a `Retry-After` header

The delay between requests is controlled by a combination of a 'backoff'
 (currently only a simple linear backoff), and honouring the
 `Retry-After` value (longest delay wins)

This makes the 'rate limiter' an optional argument as well, removing the
 use of `nil` when one isn't supplied

Signed-off-by: David Ackroyd <daveo.ackroyd@gmail.com>
This commit is contained in:
David Ackroyd
2020-05-05 13:12:29 +10:00
committed by GitHub
parent 70615279bd
commit 56e535001c
80 changed files with 791 additions and 250 deletions

View File

@@ -206,20 +206,20 @@ func ValidateSettings(b *Engine, s *Settings) {
request.MaxRequestJobs = int32(b.Settings.MaxHTTPRequestJobsLimit)
}
b.Settings.RequestTimeoutRetryAttempts = s.RequestTimeoutRetryAttempts
if b.Settings.RequestTimeoutRetryAttempts != request.DefaultTimeoutRetryAttempts && s.RequestTimeoutRetryAttempts > 0 {
request.TimeoutRetryAttempts = b.Settings.RequestTimeoutRetryAttempts
b.Settings.RequestMaxRetryAttempts = s.RequestMaxRetryAttempts
if b.Settings.RequestMaxRetryAttempts != request.DefaultMaxRetryAttempts && s.RequestMaxRetryAttempts > 0 {
request.MaxRetryAttempts = b.Settings.RequestMaxRetryAttempts
}
b.Settings.ExchangeHTTPTimeout = s.ExchangeHTTPTimeout
if s.ExchangeHTTPTimeout != time.Duration(0) && s.ExchangeHTTPTimeout > 0 {
b.Settings.ExchangeHTTPTimeout = s.ExchangeHTTPTimeout
b.Settings.HTTPTimeout = s.HTTPTimeout
if s.HTTPTimeout != time.Duration(0) && s.HTTPTimeout > 0 {
b.Settings.HTTPTimeout = s.HTTPTimeout
} else {
b.Settings.ExchangeHTTPTimeout = b.Config.GlobalHTTPTimeout
b.Settings.HTTPTimeout = b.Config.GlobalHTTPTimeout
}
b.Settings.ExchangeHTTPUserAgent = s.ExchangeHTTPUserAgent
b.Settings.ExchangeHTTPProxy = s.ExchangeHTTPProxy
b.Settings.HTTPUserAgent = s.HTTPUserAgent
b.Settings.HTTPProxy = s.HTTPProxy
if s.GlobalHTTPTimeout != time.Duration(0) && s.GlobalHTTPTimeout > 0 {
b.Settings.GlobalHTTPTimeout = s.GlobalHTTPTimeout
@@ -285,11 +285,10 @@ func PrintSettings(s *Settings) {
gctlog.Debugf(gctlog.Global, "\t Enable exchange verbose mode: %v", s.EnableExchangeVerbose)
gctlog.Debugf(gctlog.Global, "\t Enable exchange HTTP rate limiter: %v", s.EnableExchangeHTTPRateLimiter)
gctlog.Debugf(gctlog.Global, "\t Enable exchange HTTP debugging: %v", s.EnableExchangeHTTPDebugging)
gctlog.Debugf(gctlog.Global, "\t Exchange max HTTP request jobs: %v", s.MaxHTTPRequestJobsLimit)
gctlog.Debugf(gctlog.Global, "\t Exchange HTTP request timeout retry amount: %v", s.RequestTimeoutRetryAttempts)
gctlog.Debugf(gctlog.Global, "\t Exchange HTTP timeout: %v", s.ExchangeHTTPTimeout)
gctlog.Debugf(gctlog.Global, "\t Exchange HTTP user agent: %v", s.ExchangeHTTPUserAgent)
gctlog.Debugf(gctlog.Global, "\t Exchange HTTP proxy: %v\n", s.ExchangeHTTPProxy)
gctlog.Debugf(gctlog.Global, "\t Max HTTP request jobs: %v", s.MaxHTTPRequestJobsLimit)
gctlog.Debugf(gctlog.Global, "\t HTTP request max retry attempts: %v", s.RequestMaxRetryAttempts)
gctlog.Debugf(gctlog.Global, "\t HTTP timeout: %v", s.HTTPTimeout)
gctlog.Debugf(gctlog.Global, "\t HTTP user agent: %v", s.HTTPUserAgent)
gctlog.Debugf(gctlog.Global, "- GCTSCRIPT SETTINGS: ")
gctlog.Debugf(gctlog.Global, "\t Enable GCTScript manager: %v", s.EnableGCTScriptManager)
gctlog.Debugf(gctlog.Global, "\t GCTScript max virtual machines: %v", s.MaxVirtualMachines)
@@ -298,7 +297,7 @@ func PrintSettings(s *Settings) {
gctlog.Debugf(gctlog.Global, "- COMMON SETTINGS:")
gctlog.Debugf(gctlog.Global, "\t Global HTTP timeout: %v", s.GlobalHTTPTimeout)
gctlog.Debugf(gctlog.Global, "\t Global HTTP user agent: %v", s.GlobalHTTPUserAgent)
gctlog.Debugf(gctlog.Global, "\t Global HTTP proxy: %v", s.ExchangeHTTPProxy)
gctlog.Debugf(gctlog.Global, "\t Global HTTP proxy: %v", s.GlobalHTTPProxy)
gctlog.Debugln(gctlog.Global)
}

View File

@@ -59,7 +59,7 @@ type Settings struct {
EnableExchangeRESTSupport bool
EnableExchangeWebsocketSupport bool
MaxHTTPRequestJobsLimit int
RequestTimeoutRetryAttempts int
RequestMaxRetryAttempts int
// Global HTTP related settings
GlobalHTTPTimeout time.Duration
@@ -67,9 +67,9 @@ type Settings struct {
GlobalHTTPProxy string
// Exchange HTTP related settings
ExchangeHTTPTimeout time.Duration
ExchangeHTTPUserAgent string
ExchangeHTTPProxy string
HTTPTimeout time.Duration
HTTPUserAgent string
HTTPProxy string
// Dispatch system settings
EnableDispatcher bool

View File

@@ -272,19 +272,19 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
}
}
if Bot.Settings.ExchangeHTTPUserAgent != "" {
dryrunParamInteraction("exchangehttpuseragent")
exchCfg.HTTPUserAgent = Bot.Settings.ExchangeHTTPUserAgent
if Bot.Settings.HTTPUserAgent != "" {
dryrunParamInteraction("httpuseragent")
exchCfg.HTTPUserAgent = Bot.Settings.HTTPUserAgent
}
if Bot.Settings.ExchangeHTTPProxy != "" {
dryrunParamInteraction("exchangehttpproxy")
exchCfg.ProxyAddress = Bot.Settings.ExchangeHTTPProxy
if Bot.Settings.HTTPProxy != "" {
dryrunParamInteraction("httpproxy")
exchCfg.ProxyAddress = Bot.Settings.HTTPProxy
}
if Bot.Settings.ExchangeHTTPTimeout != exchange.DefaultHTTPTimeout {
dryrunParamInteraction("exchangehttptimeout")
exchCfg.HTTPTimeout = Bot.Settings.ExchangeHTTPTimeout
if Bot.Settings.HTTPTimeout != exchange.DefaultHTTPTimeout {
dryrunParamInteraction("httptimeout")
exchCfg.HTTPTimeout = Bot.Settings.HTTPTimeout
}
if Bot.Settings.EnableExchangeHTTPDebugging {