Geri aramalar (geri pingler) yoklamayı ortadan kaldırır, ancak yeni bir hata modu sunar: sunucunuz kapalı olduğunda, bir hata döndürdüğünde veya CaptchaAI sonucu sunmaya çalıştığında zaman aşımına uğradığında ne olur? Bu eğitim, CAPTCHA çözümlerini kaybetmeden geri arama hatalarını ele almaya yönelik modelleri kapsar.
Ne Yanlış Gidebilir?
| Arıza Modu | Belirti | Sonuç |
|---|---|---|
| Sunucu kapalı | CaptchaAI bağlantı reddedildi | Çözüm teslim edilmedi |
| Sunucu 5xx değerini döndürüyor | CaptchaAI hata yanıtı alıyor | Yeniden denenmeyebilir (uygulamaya bağlıdır) |
| Ağ zaman aşımı | CaptchaAI bağlantısı kilitleniyor | Çözüm potansiyel olarak kaybedildi |
| İşleyici çöküyor | İstek kabul edildi ancak sonuç saklanmadı | Çözüm sessizce bırakıldı |
Çözüm: asla yalnızca geri aramalara güvenmeyin. Her zaman bir geri dönüşünüz olsun.
Desen 1: Geri Arama + Geri Dönüş Yoklaması
En güvenilir yaklaşım, geri aramaları geldiğinde kabul etmek, ancak zaman aşımı içinde geri arama almayan tüm görevleri yoklamaktır.
Python
import os
import time
import threading
import requests
from flask import Flask, request
app = Flask(__name__)
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
# Track task state
pending_tasks = {} # task_id -> {"submitted_at": timestamp, "status": "pending"}
results = {}
lock = threading.Lock()
def submit_captcha(sitekey, pageurl, callback_url):
"""Submit with callback, but track for fallback polling."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"pingback": callback_url,
"json": 1
})
data = resp.json()
if data.get("status") == 1:
task_id = data["request"]
with lock:
pending_tasks[task_id] = {
"submitted_at": time.time(),
"status": "pending"
}
return task_id
return None
@app.route("/callback")
def captcha_callback():
"""Primary result delivery — CaptchaAI sends results here."""
task_id = request.args.get("id")
solution = request.args.get("code")
with lock:
results[task_id] = solution
pending_tasks.pop(task_id, None)
return "OK", 200
def fallback_poller():
"""Poll for any tasks that missed their callback."""
while True:
time.sleep(30) # Check every 30 seconds
with lock:
stale_tasks = [
tid for tid, info in pending_tasks.items()
if time.time() - info["submitted_at"] > 120 # 2 min callback timeout
and info["status"] == "pending"
]
for task_id in stale_tasks:
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1
})
data = resp.json()
if data.get("status") == 1:
with lock:
results[task_id] = data["request"]
pending_tasks.pop(task_id, None)
print(f"Fallback poll recovered: {task_id}")
elif data.get("request") != "CAPCHA_NOT_READY":
# Permanent error — remove from pending
with lock:
pending_tasks.pop(task_id, None)
print(f"Task failed: {task_id} — {data.get('request')}")
# Start fallback poller in background
poller_thread = threading.Thread(target=fallback_poller, daemon=True)
poller_thread.start()
JavaScript
const express = require("express");
const axios = require("axios");
const app = express();
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const pendingTasks = new Map(); // taskId -> { submittedAt, status }
const results = new Map();
async function submitCaptcha(sitekey, pageurl, callbackUrl) {
const resp = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
pingback: callbackUrl,
json: 1,
},
});
if (resp.data.status === 1) {
const taskId = resp.data.request;
pendingTasks.set(taskId, {
submittedAt: Date.now(),
status: "pending",
});
return taskId;
}
return null;
}
// Primary callback endpoint
app.get("/callback", (req, res) => {
const taskId = req.query.id;
const solution = req.query.code;
results.set(taskId, solution);
pendingTasks.delete(taskId);
res.sendStatus(200);
});
// Fallback poller
setInterval(async () => {
const now = Date.now();
const staleTasks = [];
for (const [taskId, info] of pendingTasks) {
if (now - info.submittedAt > 120000 && info.status === "pending") {
staleTasks.push(taskId);
}
}
for (const taskId of staleTasks) {
try {
const resp = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId, json: 1 },
});
if (resp.data.status === 1) {
results.set(taskId, resp.data.request);
pendingTasks.delete(taskId);
console.log(`Fallback recovered: ${taskId}`);
} else if (resp.data.request !== "CAPCHA_NOT_READY") {
pendingTasks.delete(taskId);
console.log(`Task failed: ${taskId} — ${resp.data.request}`);
}
} catch (err) {
console.error(`Poll error for ${taskId}: ${err.message}`);
}
}
}, 30000);
app.listen(3000);
Desen 2: Teslim Edilmeyecek Mektup Sırası
Geri çağırma işleyiciniz bir sonucu işlediğinde ancak bir hatayla karşılaştığında (veritabanı kapalı, doğrulama hatası), verileri kaybetmek yerine sorunu atılacaklar kuyruğuna taşıyın.
Python
import json
import os
import time
from pathlib import Path
DEAD_LETTER_DIR = Path("dead_letter")
DEAD_LETTER_DIR.mkdir(exist_ok=True)
@app.route("/callback")
def captcha_callback_with_dlq():
task_id = request.args.get("id")
solution = request.args.get("code")
try:
# Attempt normal processing
store_result(task_id, solution)
return "OK", 200
except Exception as e:
# Processing failed — save to dead-letter queue
dead_letter = {
"task_id": task_id,
"solution": solution,
"error": str(e),
"received_at": time.time()
}
dlq_path = DEAD_LETTER_DIR / f"{task_id}.json"
dlq_path.write_text(json.dumps(dead_letter))
print(f"DLQ: {task_id} — {e}")
return "OK", 200 # Still return 200 to CaptchaAI
def reprocess_dead_letters():
"""Retry processing dead-letter items."""
for dlq_file in DEAD_LETTER_DIR.glob("*.json"):
item = json.loads(dlq_file.read_text())
try:
store_result(item["task_id"], item["solution"])
dlq_file.unlink() # Remove after successful processing
print(f"DLQ reprocessed: {item['task_id']}")
except Exception:
pass # Leave in DLQ for next retry
JavaScript
const fs = require("fs");
const path = require("path");
const DLQ_DIR = path.join(__dirname, "dead_letter");
if (!fs.existsSync(DLQ_DIR)) fs.mkdirSync(DLQ_DIR);
app.get("/callback-dlq", (req, res) => {
const taskId = req.query.id;
const solution = req.query.code;
try {
storeResult(taskId, solution);
res.sendStatus(200);
} catch (err) {
// Save to dead-letter queue
const deadLetter = {
task_id: taskId,
solution: solution,
error: err.message,
received_at: Date.now(),
};
fs.writeFileSync(
path.join(DLQ_DIR, `${taskId}.json`),
JSON.stringify(deadLetter)
);
console.log(`DLQ: ${taskId} — ${err.message}`);
res.sendStatus(200); // Still acknowledge to CaptchaAI
}
});
function reprocessDeadLetters() {
const files = fs.readdirSync(DLQ_DIR).filter((f) => f.endsWith(".json"));
for (const file of files) {
const filePath = path.join(DLQ_DIR, file);
const item = JSON.parse(fs.readFileSync(filePath, "utf8"));
try {
storeResult(item.task_id, item.solution);
fs.unlinkSync(filePath);
console.log(`DLQ reprocessed: ${item.task_id}`);
} catch (err) {
// Leave in DLQ
}
}
}
// Retry DLQ every 5 minutes
setInterval(reprocessDeadLetters, 300000);
Desen 3: Idempotent Geri Arama İşleyicisi
Geri aramalar birden fazla kez yapılabilir. İşleyicinizi önemsiz hale getirin:
@app.route("/callback")
def idempotent_callback():
task_id = request.args.get("id")
solution = request.args.get("code")
with lock:
# Only process if not already handled
if task_id in results:
return "OK", 200 # Already processed — skip silently
results[task_id] = solution
pending_tasks.pop(task_id, None)
return "OK", 200
Karar Matrisi: Hangi Modelin Kullanılacağı
| Senaryo | En İyi Desen |
|---|---|
| Düşük hacim, ara sıra kesinti | Geri Arama + Geri Dönüş Yoklaması |
| Yüksek hacimli, veritabanı kesintileri mümkündür | Teslim Edilmeyen Mektup Sırası |
| Birden fazla tüketici aynı sonucu işleyebilir | İdempotent İşleyici |
| SLA'lı üretim sistemi | Üçü bir arada |
Sorun giderme
| Sorun | Sebep | Düzeltme |
|---|---|---|
| Geri dönüş yoklayıcısı zaten teslim edilmiş olan görevleri bulur | Geri arama ve anketör arasındaki yarış | Yeterlilik kontrolü ekleyin - zaten sonuçlardaysa atlayın |
| DLQ işlenmeden büyüyor | Yeniden işlemci çalışmıyor veya arızalı | Reprosesör günlüklerini kontrol edin; Temel sorunun (DB) düzeltildiğinden emin olun |
| Geri arama 200 değerini döndürür ancak sonuç kaybedilir | Yanıt gönderildikten sonra işleyici çöküyor | Yanıt vermeden önce işlem yapın veya DLQ modelini kullanın |
| Çok fazla yedek anket isteği | Çok fazla eski görev | Geri arama zaman aşımı eşiğini artırın; sunucu çalışma süresini kontrol edin |
SSS
CaptchaAI geri aramalarına her zaman 200'ü döndürmeli miyim?
Evet. Bir hata kodu (4xx/5xx) döndürmek yardımcı olmuyor - CaptchaAI geri aramaları yeniden denemeyebilir. Her zaman teslimatı kabul edin (200 OK) ve hataları DLQ veya geri dönüş yoklaması ile dahili olarak ele alın.
Geri dönüş yoklamasından önce ne kadar beklemeliyim?
Gönderimden sonra en az 120 saniye bekleyin. CAPTCHA'ların çoğu 10-60 saniye içinde çözülür ve geri arama teslimi için ağ gecikmesi eklenir. İki dakika, geri aramanın gelmesi için yeterli süreyi verir.
Geri aramaları devre dışı bırakıp sadece anket yapabilir miyim?
Evet - sadece pingback parametresini dahil etmeyin. Ancak geri aramalar, API çağrılarını büyük ölçekte önemli ölçüde azaltır (10'dan fazla yoklama isteği yerine görev başına 2 çağrı).
İlgili Makaleler
- Python Captcha Çözme Yeniden Deneme Hatası Modelleri
- Captchaai Webhook Güvenliği Geri Arama Doğrulaması
- Captchaai Hata Kodları Referansı
Sonraki Adımlar
Güvenilir CAPTCHA geri arama yönetimi oluşturun —CaptchaAI API anahtarınızı alınve bu dayanıklılık modellerini uygulayın.
İlgili kılavuzlar: