fish2018/pansou · error
[ ] 重试 次后仍然失败
Error message
[%s] 重试 %d 次后仍然失败: %w
What it means
doRequestWithRetry returns this after its final retry attempt also failed; lastErr is the error from the last attempt. Both the token fetch and the search request go through this helper, so any persistent network problem against the upstream site surfaces as this wrapped error. It signals the transport is unusable, not an HTTP-level status problem.
Solutions
- Unwrap lastErr to identify the root cause (timeout vs refused vs TLS) and fix accordingly
- Test reachability with curl from the deployment host; configure proxy env vars if needed
- Increase maxRetries or add exponential backoff for transient failures
- Increase the 30s request timeout if the upstream is consistently slow
- Retry the whole operation later; if persistent, check upstream site status
Example fix
// before
return nil, fmt.Errorf("[%s] 重试 %d 次后仍然失败: %w", p.Name(), maxRetries, lastErr)
// after
return nil, fmt.Errorf("[%s] 重试 %d 次后仍然失败 (最后一次: %v): %w", p.Name(), maxRetries, lastErr, lastErr) Defensive patterns
Strategy: retry
Validate before calling
// health probe before search
resp, err := client.Head(BaseURL)
if err != nil { return fmt.Errorf("upstream unreachable: %w", err) }
resp.Body.Close() Try / catch
if err != nil {
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
return retryAfter(2 * time.Second)
}
return nil, err // non-retryable transport failure
} Prevention
- Use exponential backoff between retries instead of immediate retry
- Verify DNS/proxy/firewall on the deployment host before blaming the library
- Cap total request time with an outer context so retries cannot hang callers
When it happens
Trigger: All maxRetries attempts in the loop returned err (dial timeout, connection refused/reset, TLS errors, context deadline exceeded) and the loop exits, wrapping lastErr.
Common situations: Site unreachable from the user's network/region; firewall or GFW blocking; DNS failure; the 30s per-request timeout expiring on a slow upstream; server-side rate limiting resetting connections.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/30a876df14357b9a.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xys/xys.go:233
backoff := time.Duration(1<<uint(i-1)) * 200 * time.Millisecond
time.Sleep(backoff)
}
// 克隆请求避免并发问题
reqClone := req.Clone(req.Context())
resp, err := client.Do(reqClone)
if err == nil && resp.StatusCode == 200 {
return resp, nil
}
if resp != nil {
resp.Body.Close()
}
lastErr = err
}
return nil, fmt.Errorf("[%s] 重试 %d 次后仍然失败: %w", p.Name(), maxRetries, lastErr)
}
// executeSearch 执行搜索请求
func (p *XysPlugin) executeSearch(client *http.Client, token, keyword string) ([]model.SearchResult, error) {
// 构建搜索URL
searchURL := fmt.Sprintf("%s%s?DToken2=%s&requestID=undefined&mode=90002&stype=undefined&scope_content=0&wd=%s&uk=&page=1&limit=20&screen_filetype=",
BaseURL, SearchPath, token, url.QueryEscape(keyword))
// 创建带超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "POST", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
}
// 设置完整的请求头View on GitHub (pinned to beaa561337)