Eğitimler

CaptchaAI Geri Arama URL'si Hata İşleme: Yeniden Deneme ve Geçersiz Harf Kalıpları

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

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:

Bu makale için yorumlar devre dışı bırakılmıştır.