fish2018/pansou · error
请求失败,已重试 次
Error message
请求失败,已重试%d次: %w
What it means
ClmaoPlugin.doRequestWithRetry has exhausted all MaxRetries attempts for an HTTP request without success. Each failed attempt records lastErr and sleeps i+1 seconds between attempts (linear backoff). After the final failure it returns this aggregate error wrapping the last transport error. Called from searchPage and fetchModernDetail, so both search and modern-detail fetching surface this on connectivity problems.
Solutions
- Unwrap the error chain to find lastErr's actual cause (timeout vs connection refused vs TLS).
- Verify outbound connectivity/DNS from the deployment environment (curl the endpoint).
- Increase TimeoutSeconds if each attempt times out; adjust MaxRetries/backoff to fit the endpoint's reliability.
- Update headers in setRequestHeaders (User-Agent, cookies) if the site started blocking the client.
- Add exponential backoff with jitter and honor Retry-After if failures correlate with rate limiting.
Example fix
// before time.Sleep(time.Duration(i+1) * time.Second) // after backoff := time.Duration(1<<uint(i)) * time.Second backoff += time.Duration(rand.Int63n(int64(time.Second))) // jitter time.Sleep(backoff)
Defensive patterns
Strategy: retry
Validate before calling
func canReach(target string) bool {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, target, nil)
if err != nil { return false }
resp, err := http.DefaultClient.Do(req)
if err != nil { return false }
resp.Body.Close()
return true
} Try / catch
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() { /* escalate timeout or circuit-break */ }
return nil, fmt.Errorf("clmao transport failure after retries: %w", err)
} Prevention
- Prefer %w so the root transport error stays inspectable with errors.Is/As.
- Use exponential backoff with jitter instead of fixed linear sleeps.
- Circuit-break after repeated total failures instead of hammering the site.
- Validate environment egress (DNS, proxy) before running batch jobs.
When it happens
Trigger: Any HTTP request issued via p.doRequestWithRetry fails on every one of MaxRetries attempts — network unreachable, DNS failure, connection reset, TLS error, or each attempt's context deadline (TimeoutSeconds) expiring. After the loop with no success: fmt.Errorf("请求失败,已重试%d次: %w", MaxRetries, lastErr).
Common situations: The clmao site is down or geo-blocked; anti-bot measures drop connections from non-browser clients; the host has no internet/DNS in containers or CI; TimeoutSeconds too short so every attempt times out.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/4323e6599dfae982.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/clmao/clmao.go:532
}
// doRequestWithRetry 带重试的HTTP请求
func (p *ClmaoPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
var lastErr error
for i := 0; i < MaxRetries; i++ {
resp, err := client.Do(req)
if err == nil {
return resp, nil
}
lastErr = err
if i < MaxRetries-1 {
time.Sleep(time.Duration(i+1) * time.Second)
}
}
return nil, fmt.Errorf("请求失败,已重试%d次: %w", MaxRetries, lastErr)
}
// init 注册插件
func init() {
plugin.RegisterGlobalPlugin(NewClmaoPlugin())
}
View on GitHub (pinned to beaa561337)