3.4 KiB
Exponential Backoff in PixivFE
PixivFE implements exponential backoff as a strategy for handling API request failures and managing token usage. This document outlines the implementation details of this feature across two key components of the application.
Overview
Exponential backoff is a technique used to gradually increase the wait time between retries of a failed operation. In PixivFE, this technique is applied at two levels:
- API request level
- Token management level
API request level backoff
Location: core/requests.go
PixivFE uses the retryablehttp package to implement exponential backoff for API requests. The implementation is as follows:
- A
retryablehttp.Clientis initialized in theinitfunction:
func init() {
retryClient = retryablehttp.NewClient()
retryClient.RetryMax = config.GlobalConfig.APIMaxRetries
retryClient.RetryWaitMin = config.GlobalConfig.APIBaseTimeout
retryClient.RetryWaitMax = config.GlobalConfig.APIMaxBackoffTime
retryClient.HTTPClient = utils.HttpClient
}
- The
retryRequestfunction uses this client to perform requests with automatic retries:
func retryRequest(ctx context.Context, reqFunc func(context.Context, string) (*retryablehttp.Request, error)) (SimpleHTTPResponse, error) {
// ... (function implementation)
}
Token management level backoff
Location: server/token_manager/token_manager.go
The TokenManager implements exponential backoff for individual tokens:
- In the
MarkTokenStatusmethod, when a token is marked asTimedOut, it calculates a timeout duration:timeoutDuration := time.Duration(math.Min( float64(tm.baseTimeout)*math.Pow(2, float64(token.FailureCount-1)), float64(tm.maxBackoffTime), )) - This calculation uses the
math.Powfunction to implement exponential growth based on the number of consecutive failures. - The timeout duration is also capped at a maximum value (
tm.maxBackoffTime). - The token's
TimeoutUntilis set to the current time plus this calculated duration.
This approach allows tokens that repeatedly fail increasingly longer "cool-down" periods before being used again, helping to manage rate limiting of individual tokens by the Pixiv API.
Implementation details
Configuration (config/config.go)
The ServerConfig struct in config/config.go includes fields for both API request level and token management level backoff settings:
type ServerConfig struct {
// ... other fields ...
MaxRetries int `env:"PIXIVFE_MAX_RETRIES,overwrite"`
BaseTimeout time.Duration `env:"PIXIVFE_BASE_TIMEOUT,overwrite"`
MaxBackoffTime time.Duration `env:"PIXIVFE_MAX_BACKOFF_TIME,overwrite"`
APIMaxRetries int `env:"PIXIVFE_API_MAX_RETRIES,overwrite"`
APIBaseTimeout time.Duration `env:"PIXIVFE_API_BASE_TIMEOUT,overwrite"`
APIMaxBackoffTime time.Duration `env:"PIXIVFE_API_MAX_BACKOFF_TIME,overwrite"`
// ... other fields ...
}
The LoadConfig method sets default values for these settings if they are not provided through environment variables:
func (s *ServerConfig) LoadConfig() error {
// ... other initializations ...
s.MaxRetries = 5
s.BaseTimeout = 1 * time.Second
s.MaxBackoffTime = 32 * time.Second
s.APIMaxRetries = 3
s.APIBaseTimeout = 500 * time.Millisecond
s.APIMaxBackoffTime = 8 * time.Second
// ... rest of the method ...
}