{"record":{"id":"d43571866e6d8756","repo":"fish2018/pansou","slug":"d-w-d43571","errorCode":null,"errorMessage":"请求重试 %d 次仍失败: %w","messagePattern":"请求重试 (.+?) 次仍失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/yulinshufa/yulinshufa.go","lineNumber":753,"sourceCode":"\t\tif attempt > 0 {\n\t\t\tbackoff := time.Duration(1<<uint(attempt-1)) * 200 * time.Millisecond\n\t\t\ttime.Sleep(backoff)\n\t\t\tp.debugf(\"重试第 %d 次, url=%s\", attempt+1, req.URL.String())\n\t\t}\n\n\t\tresp, err := client.Do(req.Clone(req.Context()))\n\t\tif err == nil && resp.StatusCode == http.StatusOK {\n\t\t\treturn resp, nil\n\t\t}\n\n\t\tif resp != nil {\n\t\t\tresp.Body.Close()\n\t\t\tlastErr = fmt.Errorf(\"状态码: %d\", resp.StatusCode)\n\t\t} else {\n\t\t\tlastErr = err\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"请求重试 %d 次仍失败: %w\", maxRetries, lastErr)\n}\n\nfunc parseDebugFlag() bool {\n\tvalue := strings.ToLower(strings.TrimSpace(os.Getenv(\"YULINSHUFA_DEBUG\")))\n\tif value == \"\" {\n\t\treturn false\n\t}\n\treturn value == \"1\" || value == \"true\" || value == \"yes\" || value == \"on\"\n}\n\nfunc (p *YulinshufaPlugin) debugf(format string, args ...interface{}) {\n\tif p.debugMode {\n\t\tlog.Printf(\"[YULINSHUFA] \"+format, args...)\n\t}\n}\n","sourceCodeStart":735,"sourceCodeEnd":769,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/yulinshufa/yulinshufa.go#L735-L769","documentation":"This error is returned by doRequestWithRetry in the yulinshufa plugin after all retry attempts have been exhausted. It wraps the last underlying error (either a non-2xx status code reported as \"状态码: %d\" or the final transport error) so callers see both the retry count and root cause. It means the upstream yulinshufa site could not be reached or did not return a successful response within maxRetries attempts.","triggerScenarios":"fetchSearchItems or getDetailResult calls doRequestWithRetry and every attempt fails — e.g. the target site returns 403/429/5xx on all retries, DNS failure, TLS errors, or network timeouts.","commonSituations":"The site is down or blocking the scraper (IP rate-limit/ban), a required cookie/anti-bot token is missing, the container has no internet or broken DNS, or the site changed its URL/anti-scraping behavior.","solutions":["Inspect the wrapped %w cause to identify whether it was a status code or a transport error","Curl the target URL from the same host to check connectivity and whether the site is blocking you","Increase retry count or add backoff delays between retries in doRequestWithRetry","Add/refresh required headers or cookies (User-Agent, anti-bot tokens) used by the plugin","If the site bans by IP, route through a proxy or wait out the rate limit"],"exampleFix":"// before\nitems, err := fetchSearchItems(keyword) // opaque retry-exhausted error\n// after\nif errors.Is(err, context.DeadlineExceeded) {\n    log.Warn(\"yulinshufa timeout, backing off\")\n    time.Sleep(5 * time.Second)\n}\nitems, err := fetchSearchItems(keyword)","handlingStrategy":"retry","validationCode":"// preflight\nresp, err := http.Head(\"https://target-site.example/search\")\nif err != nil || resp.StatusCode >= 400 {\n    log.Warn(\"upstream unreachable, skipping yulinshufa search\")\n}","typeGuard":"func isRetryExhausted(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"仍失败\")\n}","tryCatchPattern":"items, err := fetchSearchItems(ctx, keyword)\nif err != nil {\n    var retried *RetryExhaustedError\n    if errors.As(err, &retried) {\n        log.Warn(\"yulinshufa failed after retries\", \"cause\", errors.Unwrap(err))\n        return fallbackSearch(ctx, keyword)\n    }\n    return err\n}","preventionTips":["Always inspect errors.Unwrap(err) to distinguish status codes from transport errors","Add exponential backoff between retries","Keep User-Agent/cookies fresh to avoid anti-bot blocks","Monitor upstream availability and circuit-break when it degrades"],"tags":["network","http","retry-exhausted","scraping"],"backgroundTag":"http-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}