PORKBUN: Configurable retry parameters (#3746)

This commit is contained in:
James O'Gorman 2025-08-28 17:24:40 +01:00 committed by GitHub
parent 02ac788a24
commit 89ac03faca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 60 additions and 8 deletions

View file

@ -11,12 +11,32 @@ Example:
"porkbun": {
"TYPE": "PORKBUN",
"api_key": "your-porkbun-api-key",
"secret_key": "your-porkbun-secret-key",
"secret_key": "your-porkbun-secret-key"
}
}
```
{% endcode %}
Porkbun has quite strict API limits. If you experience errors with this provider (common when you have many domains), you can set one or both of `max_attempts` and `max_duration` in the credentials configuration.
Example:
{% code title="creds.json" %}
```json
{
"porkbun": {
"TYPE": "PORKBUN",
"api_key": "your-porkbun-api-key",
"secret_key": "your-porkbun-secret-key",
"max_attempts": "10",
"max_duration": "5m"
}
}
```
{% endcode %}
The default for `max_attempts` is 5. There is no maximum duration by default, instead the provider will perform exponential backoff between 1 and 10 seconds, until `max_attempts` is reached. To retry indefinitely until `max_duration` is reached, set `max_attempts` to any value below 1.
## Metadata
This provider does not recognize any special metadata fields unique to Porkbun.

View file

@ -292,6 +292,8 @@
"TYPE": "PORKBUN",
"api_key": "$PORKBUN_API_KEY",
"domain": "$PORKBUN_DOMAIN",
"max_attempts": "$PORKBUN_MAX_ATTEMPTS",
"max_duration": "$PORKBUN_MAX_DURATION",
"secret_key": "$PORKBUN_SECRET_KEY"
},
"POWERDNS": {

View file

@ -24,6 +24,9 @@ const (
type porkbunProvider struct {
apiKey string
secretKey string
maxAttempts int
maxDuration time.Duration
}
type requestParams map[string]any
@ -74,17 +77,22 @@ func (c *porkbunProvider) post(endpoint string, params requestParams) ([]byte, e
}
retryPolicy := failsafehttp.RetryPolicyBuilder().
WithMaxRetries(5).
// Exponential backoff between 1 and 10 seconds
WithBackoff(time.Second, 10*time.Second).
WithMaxAttempts(c.maxAttempts).
// Exponential backoff between 1.2 and 10 seconds.
// We start at 1.2 to allow for 100ms of jitter. Porkbun doesn't like
// retries faster than 1s.
WithBackoff(1200*time.Millisecond, 10*time.Second).
WithJitter(100 * time.Millisecond).
OnRetryScheduled(func(f failsafe.ExecutionScheduledEvent[*http.Response]) {
printer.Debugf("Porkbun API response code %d, waiting for %s until next attempt\n", f.LastResult().StatusCode, f.Delay)
}).
Build()
})
if c.maxDuration > 0 {
retryPolicy = retryPolicy.WithMaxDuration(c.maxDuration)
}
client := &http.Client{
Transport: failsafehttp.NewRoundTripper(nil, retryPolicy),
Transport: failsafehttp.NewRoundTripper(nil, retryPolicy.Build()),
}
req, _ := http.NewRequest(http.MethodPost, baseURL+endpoint, bytes.NewBuffer(paramsJSON))

View file

@ -7,6 +7,7 @@ import (
"sort"
"strconv"
"strings"
"time"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
@ -25,6 +26,10 @@ const (
metaWildcard = "wildcard"
)
const (
defaultMaxAttempts = 5
)
// https://kb.porkbun.com/article/63-how-to-switch-to-porkbuns-nameservers
var defaultNS = []string{
"curitiba.ns.porkbun.com",
@ -43,7 +48,9 @@ func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServ
// newPorkbun creates the provider.
func newPorkbun(m map[string]string, _ json.RawMessage) (*porkbunProvider, error) {
c := &porkbunProvider{}
c := &porkbunProvider{
maxAttempts: defaultMaxAttempts,
}
c.apiKey, c.secretKey = m["api_key"], m["secret_key"]
@ -51,6 +58,21 @@ func newPorkbun(m map[string]string, _ json.RawMessage) (*porkbunProvider, error
return nil, errors.New("missing porkbun api_key or secret_key")
}
if maxAttempts, ok := m["max_attempts"]; ok && maxAttempts != "" {
i, err := strconv.Atoi(maxAttempts)
if err != nil {
return nil, fmt.Errorf("porkbun: invalid max_attempts %q: must be a whole number", maxAttempts)
}
c.maxAttempts = i
}
if maxDuration, ok := m["max_duration"]; ok && maxDuration != "" {
d, err := time.ParseDuration(maxDuration)
if err != nil {
return nil, fmt.Errorf("porkbun: invalid max_duration %q: valid units are ns, us, ms, s, m, h", maxDuration)
}
c.maxDuration = d
}
return c, nil
}