fish2018/pansou · error

重试 次后失败

Error message

重试 %d 次后失败: %w

What it means

doRequestWithRetry performs HTTP requests with exponential backoff (retryBaseDelay * 2^attempt) for up to maxRetries attempts. If every attempt fails, it returns this error wrapping the last underlying error with %w. It aggregates persistent transport failures after exhausting the retry budget.

Solutions

  1. Inspect the wrapped lastErr (errors.Unwrap / %w chain) to find the true root cause (timeout, connection refused, TLS).
  2. Confirm network egress and DNS resolution from the host running the plugin.
  3. Increase maxRetries or retryBaseDelay if the upstream is intermittently slow or rate limiting.
  4. Retry later if the target site is temporarily down; consider a proxy or alternate mirror.

Example fix

// before
res, err := p.doRequestWithRetry(client, url)
if err != nil { return err }
// after
res, err := p.doRequestWithRetry(client, url)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        return fmt.Errorf("upstream timeout, try increasing client timeout: %w", err)
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight reachability check
if _, err := net.LookupTimeout(ctx, "tcp", host+":443", 5*time.Second); err != nil {
    return fmt.Errorf("host unreachable before request: %w", err)
}

Try / catch

if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        // schedule retry with longer backoff
    }
    return fmt.Errorf("all retries exhausted: %w", err)
}

Prevention

When it happens

Trigger: Any call chain through searchImpl or fetchDetailLinks that reaches doRequestWithRetry while the target host is unreachable, times out, resets connections, or returns repeatedly failing responses on all maxRetries attempts.

Common situations: Site is down or blocking the client; DNS failure in the deployment environment; timeout too aggressive for a slow upstream; corporate proxy/firewall blocking outbound requests; retryBaseDelay/backoff insufficient during rate limiting.

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/b8201fa86b74bf57. Report an issue: GitHub.

Appendix: source

Thrown at plugin/daishudj/daishudj.go:436

}

func (p *DaishuPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
	var lastErr error
	for attempt := 0; attempt < maxRetries; attempt++ {
		resp, err := client.Do(req.Clone(req.Context()))
		if err == nil && resp.StatusCode == http.StatusOK {
			return resp, nil
		}
		if resp != nil {
			resp.Body.Close()
		}
		lastErr = err
		if attempt < maxRetries-1 {
			backoff := retryBaseDelay * time.Duration(1<<attempt)
			time.Sleep(backoff)
		}
	}
	return nil, fmt.Errorf("重试 %d 次后失败: %w", maxRetries, lastErr)
}

func startCacheCleaner() {
	ticker := time.NewTicker(cacheCleanupInterval)
	defer ticker.Stop()

	for range ticker.C {
		now := time.Now()
		detailCache.Range(func(key, value interface{}) bool {
			entry, ok := value.(cacheEntry)
			if !ok || now.After(entry.expiresAt) {
				detailCache.Delete(key)
			}
			return true
		})
	}
}

View on GitHub (pinned to beaa561337)