mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-09-07 13:44:18 +08:00
TRANSIP: Pause when rate-limited (#3378)
This commit is contained in:
parent
f666af8714
commit
5cfb9073a2
2 changed files with 97 additions and 1 deletions
76
providers/transip/retry.go
Normal file
76
providers/transip/retry.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package transip
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/transip/gotransip/v6/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
initialBackoff = time.Second * 20 // First delay duration
|
||||
maxBackoff = time.Minute * 4 // Maximum backoff delay
|
||||
)
|
||||
|
||||
// backoff is the amount of time to sleep if a 429 (or similar) is received.
|
||||
// It is doubled after each use.
|
||||
var (
|
||||
backoff = initialBackoff
|
||||
)
|
||||
|
||||
func retryNeeded(err error) bool {
|
||||
if err == nil {
|
||||
return false // Not an error.
|
||||
}
|
||||
|
||||
serr, ok := err.(*rest.Error)
|
||||
if !ok {
|
||||
return false // Not an error we know how to work with.
|
||||
}
|
||||
|
||||
if serr.StatusCode == 200 {
|
||||
backoff = initialBackoff // Reset
|
||||
return false // Success! No need to retry.
|
||||
}
|
||||
|
||||
if serr.StatusCode != 429 {
|
||||
return false
|
||||
}
|
||||
|
||||
// a simple exponential back-off
|
||||
log.Printf("Pausing due to ratelimit (%03d): %v seconds\n", serr.StatusCode, backoff)
|
||||
time.Sleep(backoff)
|
||||
backoff = backoff + (backoff / 2)
|
||||
if backoff > maxBackoff {
|
||||
backoff = maxBackoff
|
||||
}
|
||||
|
||||
return true // Request the API call be re-tried.
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
TODO(tlim): Use X-Rate-Limit-Reset to optimize sleep time.
|
||||
|
||||
This is a rather lazy implementation. A better implementation would examine
|
||||
the X-Rate-Limit-Reset header and wait until that timestamp, if the timestamp
|
||||
seems reasonable. This implementation just does an exponential back-off.
|
||||
|
||||
This is what the documentation says:
|
||||
|
||||
> **Rate limit**
|
||||
> The rate limit for this API uses a sliding window of 15 minutes. Within this window, a maximum of 1000 requests can be made per user.
|
||||
>
|
||||
> Every request returns the following headers, indicating the number of requests made within this window, the amount of requests remaining and the reset timestamp.
|
||||
>
|
||||
> ```text
|
||||
> X-Rate-Limit-Limit: 1000
|
||||
> X-Rate-Limit-Remaining: 650
|
||||
> X-Rate-Limit-Reset: 1485875578
|
||||
> ```
|
||||
|
||||
> When this rate limit is exceeded, the response contains an error with HTTP status code: `429: Too many requests`.
|
||||
|
||||
<https://api.transip.nl/rest/docs.html#header-rate-limit>
|
||||
|
||||
*/
|
|
@ -99,10 +99,15 @@ func init() {
|
|||
func (n *transipProvider) ListZones() ([]string, error) {
|
||||
var domains []string
|
||||
|
||||
retry:
|
||||
domainsMap, err := n.domains.GetAll()
|
||||
if retryNeeded(err) {
|
||||
goto retry
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, domainname := range domainsMap {
|
||||
domains = append(domains, domainname.Name)
|
||||
}
|
||||
|
@ -136,7 +141,13 @@ func (n *transipProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, cur
|
|||
return err
|
||||
}
|
||||
|
||||
return n.domains.ReplaceDNSEntries(dc.Name, nativeDNSEntries)
|
||||
retry:
|
||||
err = n.domains.ReplaceDNSEntries(dc.Name, nativeDNSEntries)
|
||||
if retryNeeded(err) {
|
||||
goto retry
|
||||
}
|
||||
return err
|
||||
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -146,7 +157,11 @@ func (n *transipProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, cur
|
|||
|
||||
// GetZoneRecords returns all records within given zone
|
||||
func (n *transipProvider) GetZoneRecords(domainName string, meta map[string]string) (models.Records, error) {
|
||||
retry:
|
||||
entries, err := n.domains.GetDNSEntries(domainName)
|
||||
if retryNeeded(err) {
|
||||
goto retry
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -167,10 +182,15 @@ func (n *transipProvider) GetZoneRecords(domainName string, meta map[string]stri
|
|||
func (n *transipProvider) GetNameservers(domainName string) ([]*models.Nameserver, error) {
|
||||
var nss []string
|
||||
|
||||
retry:
|
||||
entries, err := n.domains.GetNameservers(domainName)
|
||||
if retryNeeded(err) {
|
||||
goto retry
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
nss = append(nss, entry.Hostname)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue