Captcha solver error handling - retries, backoff और कभी retry न करने वाली errors
Captcha solve एक network call है, एक ऐसी system के लिए जिसे आप नियंत्रित नहीं करते, और एक ऐसे challenge के खिलाफ़ जो बिना चेतावनी के बदल सकता है। Failures को अच्छी तरह संभालना ही उस pipeline और उस pipeline के बीच का फ़र्क है जो सुचारू रूप से कम होती रहती है, और उस pipeline के बीच जो retry storm में समय बर्बाद करती है।
Scarnox में economics आपकी मदद करता है: विफल solves मुफ़्त हैं, इसलिए retry में केवल समय लगता है, और कुछ नहीं। पर गलत failure को retry करने से भी वह समय बर्बाद होता है, और ज़रूरत से ज़्यादा retry करने से अपनी अलग समस्याएँ हो सकती हैं। यह guide एक retry policy देती है जिसे आप Python job में paste कर सकते हैं।
Scarnox आज PopularCaptcha solve करता है। यही error handling किसी भी captcha solver पर लागू होता है, इसलिए नीचे की policy captcha type पर निर्भर नहीं करती।
हमेशा पहले errorId जाँचें
Solve response में एक errorId field होता है। 0 का मतलब सफलता है और token solution.token के नीचे होता है। कोई और मान बताता है कि solve विफल हुआ। विफल response में errorCode और errorDescription भी होते हैं। दोनों लॉग करें: code वह है जिसे आप बाद में खोजेंगे, और description वह है जो तब पढ़ेंगे जब run गड़बड़ हो।
{"errorId": 1, "errorCode": "...", "errorDescription": "..."}
यह कभी न मानें कि response सफल है क्योंकि HTTP status 200 है। हर बार errorId जाँचें।
जिन failures को retry करना है
कुछ failures अस्थायी होती हैं। इन्हें exponential backoff और एक छोटे random delay के साथ retry करें:
- Network errors: connection resets, DNS की गड़बड़ी, आपकी तरफ़ से read timeouts।
- Server errors: HTTP 5xx responses, जिसका मतलब service की तरफ़ की समस्या है।
- Rate limiting: HTTP 429, जिसका मतलब है कि आप requests बहुत तेज़ भेज रहे हैं। धीमे हों।
- Timeouts: solve आपके client के इंतज़ार से ज़्यादा चला। अगर आपने पहले से लंबा timeout नहीं सेट किया है, तो उसके साथ retry करें।
इन failures की retry सार्थक है, क्योंकि अगली कोशिश बिना आपकी तरफ़ से किसी बदलाव के सफल हो सकती है।
जिन failures को retry से पहले ठीक करना है
कुछ failures इंतज़ार से नहीं जाएँगी। वही input के साथ retry उसी तरह फ़ेल होगा। इन्हें पहले ठीक करें:
- अमान्य task type। जाँचें कि
captcha_typedocs में लिखे अनुसार सही spelled है। - गलत या गायब sitekey। Page से sitekey फिर से पढ़ें। पुराने deploy की sitekey एक आम कारण है।
- गलत page URL।
site_urlवही page होना चाहिए जो widget दिखाता है। - Proxy की समस्याएँ। मरा हुआ, गलत लिखा या block हुआ proxy हर प्रयास को फ़ेल करेगा। पहले proxy को अकेले टेस्ट करें। proxy बनाम proxyless देखें।
- Account की समस्याएँ। अमान्य key या ज़रूरी balance न होने वाला account हर प्रयास को तब तक फ़ेल करेगा जब तक कोई उसे ठीक न करे। किसी व्यक्ति को सूचित करें; loop में retry न करें।
जब कोई failure दोनों सूचियों में न हो, तो उसे पहले ठीक करने वाली failure मानें। Error text देखें, फ़ैसला करें, और code को सही सूची में जोड़ें। ये सूचियाँ छोटी और समीक्षित रखें।
एक policy जिसे आप paste कर सकें
import os
import random
import time
import requests
API_URL = "https://api.scarnox.com/api/tasks/create"
HEADERS = {"Authorization": f"Bearer {os.environ['SCARNOX_KEY']}"}
MAX_ATTEMPTS = 4
class SolveError(Exception):
def __init__(self, code: str, description: str, retryable: bool):
super().__init__(f"{code}: {description}")
self.code = code
self.retryable = retryable
def solve_once(payload: dict) -> str:
try:
r = requests.post(API_URL, headers=HEADERS, json=payload, timeout=185)
except requests.RequestException as exc:
# हमारी तरफ़ network error या timeout: retry सुरक्षित है।
raise SolveError("NETWORK", str(exc), retryable=True)
if r.status_code == 429 or r.status_code >= 500:
raise SolveError(f"HTTP_{r.status_code}", r.text[:200], retryable=True)
try:
data = r.json()
except ValueError:
raise SolveError(f"HTTP_{r.status_code}", r.text[:200], retryable=False)
if data.get("errorId") == 0:
return data["solution"]["token"]
# API ने failure बताया। केवल वही codes retry करें जो आपने अस्थायी पाए हों।
code = data.get("errorCode", "UNKNOWN")
retryable = code in TRANSIENT_CODES
raise SolveError(code, data.get("errorDescription", ""), retryable=retryable)
# API error codes यहाँ तभी जोड़ें जब आपके logs में वे अस्थायी दिखें।
TRANSIENT_CODES: set[str] = set()
def solve(payload: dict) -> str:
for attempt in range(MAX_ATTEMPTS):
try:
return solve_once(payload)
except SolveError as err:
last_attempt = attempt == MAX_ATTEMPTS - 1
if not err.retryable or last_attempt:
raise
delay = min(30, 2 ** attempt) + random.random() # backoff + jitter (थोड़ा random delay)
print(f"attempt {attempt + 1} failed ({err.code}), retrying in {delay:.1f}s")
time.sleep(delay)
raise RuntimeError("unreachable")
Policy कभी ऐसी failure को retry नहीं करती जिसे पहले ठीक करना है, और वह एक तय संख्या के प्रयासों के बाद रुक जाती है। TRANSIENT_CODES set जानबूझकर खाली शुरू होता है: कोई code तभी जोड़ें जब आपके logs दिखाएँ कि वह अस्थायी है।
Jitter क्यों मायने रखता है
अगर पचास workers एक ही पल में फ़ेल हों और सब ठीक दो सेकंड सोएँ, तो वे सब एक साथ retry करेंगे और फिर एक साथ फ़ेल होंगे। आधा सेकंड का random हिस्सा उन्हें फैला देता है। बड़े API providers अपने clients को भी यही सलाह देते हैं।
Timeouts
HTTP timeout को आम solve समय से काफ़ी ऊपर रखें, लगभग 185 सेकंड। Request तब तक रुकती है जब तक token तैयार न हो, इसलिए छोटा client timeout एक धीमी सफलता को ऐसी विफलता में बदल सकता है जिसे आप बेकार में retry करते हैं। Solve से लंबा client timeout ही सुरक्षित सेटिंग है।
Tokens cache नहीं होते
Token लगभग दो मिनट में expire होता है। Tokens को runs के बीच cache न करें, और एक ही token को दूसरे submission के लिए दोबारा इस्तेमाल न करें। अगर token इस्तेमाल होने के बाद submit विफल हो, तो पुराना token दोबारा submit करने के बजाय फिर से solve करें। token expiry guide समय का विवरण देती है।
कई workers के बीच concurrency और backoff
अगर कई workers एक key साझा करते हैं, तो एक worker का backoff बाकियों को धीमा नहीं करता। समवर्ती solves पर एक साझा सीमा जोड़ें, जैसे semaphore या queue, ताकि retries का burst requests के burst में न बदले। एक सरल concurrency cap ही ज़्यादातर rate-limit failures को शुरू होने से पहले रोक देता है।
ऐसा logging जो मदद करे
हर विफल प्रयास के लिए errorCode, प्रयास संख्या, sitekey, page host और यह लॉग करें कि failure retry हुई या नहीं। API key या proxy password कभी लॉग न करें। एक dashboard जो हर घंटे codes गिनता है, आपको जल्दी बताता है कि समस्या आपके code में है, proxy में है या service में।
अगले कदम
- Python में PopularCaptcha कैसे solve करें
- Proxy या proxyless: कौन-सा task type चाहिए?
- आपके app में captcha हो तो CI हरा कैसे रखें
- मुफ़्त captcha solver trial
अपनी handling को मुफ़्त trial पर टेस्ट करें: खाता बनाएँ और मुफ़्त ट्रायल क्रेडिट से शुरू करें, कार्ड की ज़रूरत नहीं।