Callback'iniz teslimatı başarısız olursa çözüm otomatik olarak kaybolmaz — doğru fallback deseniniz varsa. CaptchaAI sonucu callback URL'inize göndermeye çalışırken sunucunuz kapalıysa, 5xx dönerse veya bağlantı zaman aşımına uğrarsa üç desenden biri devreye girmeli:
- Callback + yedek sorgulama — callback zamanında gelmezse arka planda sonucu sorgulayın.
- Dead-letter queue (DLQ) — işleyici hata verirse sonucu kaybetmeyin, kuyruğa taşıyın.
- Idempotent işleyici — aynı callback iki kez gelse bile veriyi bozmayın.
Bu rehber üçünü de çalışan kod örnekleriyle gösterir ve hangi senaryoda hangisini seçeceğinizi netleştirir.
Callback Teslimatı Neden Başarısız Olur?
Üretimde callback güvenilirliği tipik olarak dört noktada kırılır:
| Arıza Noktası | Belirti | Sonuç |
|---|---|---|
| Sunucu kapalı | CaptchaAI bağlantı reddi alır | Çözüm teslim edilmez |
| Sunucu 5xx döner | CaptchaAI hata yanıtı alır | Yeniden deneme uygulamaya bağlıdır — garanti değil |
| Ağ zaman aşımı | CaptchaAI bağlantısı asılı kalır | Çözüm kaybolma riski taşır |
| İşleyici çöker | İstek kabul edilir, sonuç kaydedilmez | Çözüm sessizce kaybolur |
Callback'e asla tek başına güvenmeyin. Her zaman bir geri dönüş mekanizmanız olsun.
Hangi Deseni Ne Zaman Kullanmalısınız?
Üç deseni ayrı ayrı ya da birlikte kullanabilirsiniz; seçim trafik hacminize ve SLA'nıza bağlıdır. Aşağıda hızlı bir özet, ardından her deseni kod örnekleriyle görebilirsiniz.
| Senaryo | Önerilen Desen |
|---|---|
| Düşük hacim, ara sıra kesinti | Callback + Yedek Sorgulama |
| Yüksek hacim, veritabanı kesintisi olasılığı var | Dead-Letter Queue |
| Aynı sonucu birden fazla tüketici işleyebilir | Idempotent İşleyici |
| SLA'lı üretim sistemi | Üçü birlikte |
Desen 1: Callback + Yedek Sorgulama
En dayanıklı yaklaşım, callback'leri geldiği anda kabul etmek ama zaman aşımı süresi içinde callback almayan görevleri arka planda periyodik olarak sorgulamaktır. Aşağıdaki Python ve Node.js örnekleri aynı mantığı uygular: görevi gönderin, bekleyen listesine ekleyin, callback gelirse listeden çıkarın, gelmezse 30 saniyede bir arka planda sorgulayın.
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);
Örnek senaryo:
Europe/Istanbulsaat diliminde çalışan bir e-ticaret entegrasyon projesinde callback sunucunuz gece bakım penceresinde birkaç dakika erişilemez durumda kalıyorsa, yedek sorgulama o pencerede kaybolan görevleri kurtarır; callback tekrar ayağa kalktığında akış kendiliğinden normale döner.
Desen 2: Dead-Letter Queue (Teslim Edilemeyen Görev Kuyruğu)
Callback işleyiciniz sonucu aldı ama veritabanı kapalıysa veya doğrulama hatası oluşuyorsa, veriyi kaybetmek yerine dead-letter queue'ya (DLQ) taşıyın. Üretimde en çok tercih edilen desen budur, çünkü hatayı gözlemlenebilir hale getirir — sessizce kaybetmek yerine dead_letter/ klasöründe (veya gerçek bir kuyruk servisinde) saklar.
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);
KVKK notu: DLQ kayıtları hata ayıklama içindir, kalıcı arşiv değildir. Özellikle test/QA verisi içeren görevleri makul bir saklama süresinden sonra otomatik temizleyin — gereksiz veri birikimi KVKK kapsamında ayrı bir risk oluşturur.
Desen 3: Idempotent Callback İşleyicisi
Callback'ler bazen birden fazla kez teslim edilebilir — ağ tekrarları veya yük dengeleyici davranışları yüzünden. İşleyicinizi idempotent yapın: aynı task_id ikinci kez geldiğinde sessizce 200 dönün, veriyi tekrar yazmayın.
@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
Sık Sorulan Sorular
CaptchaAI callback davranışı hakkında geliştiricilerin en çok sorduğu beş soru:
Callback URL'imi yerel ortamda (localhost) nasıl test ederim?
Flask veya Express sunucunuzu bir tünel aracıyla (örneğin ngrok veya cloudflared) dışarı açın ve pingback parametresine geçici tünel adresini verin. Callback'i canlıya almadan önce uçtan uca yerelde doğrulamış olursunuz.
CaptchaAI callback'lerine her zaman HTTP 200 mü dönmeliyim?
Evet. Hata kodu (4xx/5xx) döndürmek işe yaramaz — CaptchaAI callback'i yeniden denemeyebilir. Teslimatı her zaman kabul edin (200 OK), hatayı DLQ veya yedek sorgulama ile dahili olarak yönetin.
Yedek sorgulamayı gönderimden kaç saniye sonra başlatmalıyım?
En az 120 saniye bekleyin. CAPTCHA'ların çoğu 10–60 saniyede çözülür, buna callback teslim gecikmesi eklenir; iki dakika callback'in ulaşması için yeterli pay bırakır.
Dead-letter queue'da biriken görevleri ne kadar süre saklamalıyım?
Sabit bir kural yok, ama gereksiz veri birikimini önlemek için makul bir saklama süresi (örneğin 7–30 gün) belirleyip otomatik temizleyin — özellikle DLQ kayıtları test/QA verisi içeriyorsa.
Aynı görev için callback iki kez gelirse ne olur?
CaptchaAI ağ katmanında aynı sonucu iki kez gönderebilir. İdempotent işleyici deseniyle ikinci teslimat sessizce 200 döner ve veriyi tekrar yazmaz — bkz. Desen 3.
Uygulamaya Nasıl Başlarsınız?
- Görev gönderirken
pingbackparametresine callback URL'inizi ekleyin ve uç noktayı yerelde ngrok gibi bir tünel aracıyla test edin. - Düşük trafikte bile Desen 1'i (callback + yedek sorgulama) devreye alın — tek başına temel bir güvence sağlar.
- Hacim büyüdükçe Desen 2'yi (DLQ) ve Desen 3'ü (idempotent işleyici) ekleyin; SLA'lı üretim sistemlerinde üçünü birlikte kullanmak önerilir.
Sorun Giderme
Üretimde callback işleyicilerinde en sık karşılaşılan dört sorun ve çözümü:
- Yedek sorgulama zaten teslim edilmiş görevleri tekrar buluyor — callback ile sorgulama arasındaki yarış durumundandır; idempotency kontrolü ekleyin, sonuçlarda varsa atlayın.
- DLQ işlenmeden büyüyor — yeniden işleyici çalışmıyor veya hata veriyordur; loglarını kontrol edin ve kök nedeni (DB) düzeltin.
- Callback 200 dönüyor ama sonuç kayboluyor — işleyici yanıt gönderildikten sonra çöküyordur; yanıtı göndermeden önce işleyin veya DLQ desenini kullanın.
- Çok fazla yedek sorgulama isteği geliyor — çok fazla eski görev birikmiştir; callback zaman aşımı eşiğini artırın ve sunucu çalışma süresini kontrol edin.
İlgili Makaleler
Konuyu derinleştirmek isterseniz Python captcha çözümlerinde yeniden deneme ve hata desenlerine göz atın, callback imzalarını doğrulamak için webhook güvenliği rehberine bakın ve hata kodlarının tam listesi için CaptchaAI hata kodları referansını kaynak olarak kullanın.
Sonraki Adımlar
Callback hata yönetiminizi bugün sağlamlaştırın — CaptchaAI API anahtarınızı alın ve bu üç dayanıklılık desenini uygulayın. Kurulumu tamamladıktan sonra callback URL ve webhook kurulum rehberini, pingback görev bildirimi desenlerini ve webhook güvenliği: callback doğrulama rehberini de inceleyin.