API Eğitimleri

CAPTCHA API Çağrıları için Devre Kesici Kalıbı

CAPTCHA çözme API'si yavaş olduğunda veya hata döndürdüğünde, istek göndermeye devam etmek zaman ve para kaybına neden olur. Devre kesici modeli, arızalı bir API'nin çağrılmasını durdurur, kurtarmayı bekler ve otomatik olarak devam ederek işlem hattınızda art arda arızaların oluşmasını önler.


Devre kesiciler nasıl çalışır?

Üç durum:

  1. Kapalı – Normal çalışma. Talepler geçiyor. Başarısızlıklar sayılır.
  2. Açık – Çok fazla hata var. Tüm istekler, API çağrılmadan hemen reddedilir.
  3. Yarı Açık – Bir soğuma süresinden sonra bir test isteğinin geçmesine izin verilir. Başarılı olursa devre kapanır. Başarısız olursa devre tekrar açılır.

Python uygulaması

import time
import threading
import requests

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
API_KEY = "YOUR_API_KEY"


class CircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=60):
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.failure_count = 0
        self.last_failure_time = 0
        self.state = "closed"  # closed, open, half-open
        self._lock = threading.Lock()

    def call(self, func, *args, **kwargs):
        with self._lock:
            if self.state == "open":
                if time.time() - self.last_failure_time > self.recovery_timeout:
                    self.state = "half-open"
                    print("[circuit] State: half-open — testing one request")
                else:
                    remaining = self.recovery_timeout - (
                        time.time() - self.last_failure_time
                    )
                    raise CircuitOpenError(
                        f"Circuit open — retry in {remaining:.0f}s"
                    )

        try:
            result = func(*args, **kwargs)
            with self._lock:
                self.failure_count = 0
                if self.state == "half-open":
                    print("[circuit] State: closed — API recovered")
                self.state = "closed"
            return result
        except Exception as e:
            with self._lock:
                self.failure_count += 1
                self.last_failure_time = time.time()
                if self.failure_count >= self.failure_threshold:
                    self.state = "open"
                    print(
                        f"[circuit] State: open — "
                        f"{self.failure_count} failures"
                    )
            raise


class CircuitOpenError(Exception):
    pass


def solve_captcha(sitekey, page_url):
    resp = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "json": "1",
    }, timeout=15)
    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"Submit error: {data['request']}")

    task_id = data["request"]
    for _ in range(24):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": "1",
        }, timeout=15).json()
        if poll["status"] == 1:
            return poll["request"]
        if poll["request"] != "CAPCHA_NOT_READY":
            raise Exception(f"Poll error: {poll['request']}")
    raise TimeoutError(f"Task {task_id} timed out")


# Usage
breaker = CircuitBreaker(failure_threshold=3, recovery_timeout=30)

for i in range(10):
    try:
        token = breaker.call(
            solve_captcha, "6Le-SITEKEY", "https://example.com"
        )
        print(f"[task-{i}] Solved: {token[:40]}...")
    except CircuitOpenError as e:
        print(f"[task-{i}] Skipped: {e}")
    except Exception as e:
        print(f"[task-{i}] Failed: {e}")

Beklenen çıktı:

[task-0] Solved: 03AGdBq26ZfPxL...
[task-1] Solved: 03AGdBq27AbCdE...
[task-2] Failed: Submit error: ERROR_NO_SLOT_AVAILABLE
[task-3] Failed: Submit error: ERROR_NO_SLOT_AVAILABLE
[task-4] Failed: Submit error: ERROR_NO_SLOT_AVAILABLE
[circuit] State: open — 3 failures
[task-5] Skipped: Circuit open — retry in 28s
[task-6] Skipped: Circuit open — retry in 25s
...
[circuit] State: half-open — testing one request
[task-8] Solved: 03AGdBq28FgHiJ...
[circuit] State: closed — API recovered

JavaScript uygulaması

class CircuitBreaker {
  constructor(options = {}) {
    this.failureThreshold = options.failureThreshold || 5;
    this.recoveryTimeout = options.recoveryTimeout || 60000;
    this.failureCount = 0;
    this.lastFailureTime = 0;
    this.state = 'closed';
  }

  async call(fn, ...args) {
    if (this.state === 'open') {
      if (Date.now() - this.lastFailureTime > this.recoveryTimeout) {
        this.state = 'half-open';
        console.log('[circuit] State: half-open');
      } else {
        const remaining = this.recoveryTimeout - (Date.now() - this.lastFailureTime);
        throw new Error(`Circuit open — retry in ${Math.ceil(remaining / 1000)}s`);
      }
    }

    try {
      const result = await fn(...args);
      this.failureCount = 0;
      if (this.state === 'half-open') {
        console.log('[circuit] State: closed — recovered');
      }
      this.state = 'closed';
      return result;
    } catch (error) {
      this.failureCount++;
      this.lastFailureTime = Date.now();
      if (this.failureCount >= this.failureThreshold) {
        this.state = 'open';
        console.log(`[circuit] State: open — ${this.failureCount} failures`);
      }
      throw error;
    }
  }
}

// Usage
const axios = require('axios');

const API_KEY = 'YOUR_API_KEY';
const breaker = new CircuitBreaker({ failureThreshold: 3, recoveryTimeout: 30000 });

async function solveCaptcha(sitekey, pageurl) {
  const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
    params: { key: API_KEY, method: 'userrecaptcha', googlekey: sitekey, pageurl, json: 1 }
  });

  if (submit.data.status !== 1) throw new Error(submit.data.request);
  const taskId = submit.data.request;

  for (let i = 0; i < 24; i++) {
    await new Promise(r => setTimeout(r, 5000));
    const poll = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: API_KEY, action: 'get', id: taskId, json: 1 }
    });
    if (poll.data.status === 1) return poll.data.request;
    if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
  }
  throw new Error('Timeout');
}

(async () => {
  for (let i = 0; i < 10; i++) {
    try {
      const token = await breaker.call(solveCaptcha, '6Le-SITEKEY', 'https://example.com');
      console.log(`[task-${i}] Solved: ${token.substring(0, 40)}...`);
    } catch (err) {
      console.log(`[task-${i}] ${err.message}`);
    }
  }
})();

Eşikleri seçme

Parametre Düşük trafik (< 10/min) Yüksek trafik (> 100/min)
failure_threshold 3 10
recovery_timeout 30'lar 60'lar

Arıza eşiğini, aralıklı hataları tolere edecek kadar yüksek (tek bir zaman aşımı devreyi tetiklememelidir), ancak arızalı bir API'yi etkilemeyi durduracak kadar da düşük ayarlayın.


Yeniden deneme mantığıyla birleştirme

Devre kesicinin içindeki yeniden deneme mantığını kullanın. Devre kesici son arızaları sayar (yeniden denemeler bittikten sonra):

def solve_with_retry(sitekey, page_url, max_retries=2):
    for attempt in range(max_retries + 1):
        try:
            return solve_captcha(sitekey, page_url)
        except Exception:
            if attempt == max_retries:
                raise
            time.sleep(2 ** attempt)

# Circuit breaker wraps the retry function
token = breaker.call(solve_with_retry, "6Le-SITEKEY", "https://example.com")

Sorun giderme

Sorun Sebep Düzeltme
Devre çok hızlı açılıyor Eşik çok düşük failure_threshold'yi artırın
Devre asla düzelmez recovery_timeout çok uzun 30-60 saniyeye düşürün
Çok iş parçacıklı kullanımda yarış durumu Durumda kilit yok threading.Lock (Python) veya atomik işlemleri kullanın
Kısmi kesinti sırasında tüm istekler engellendi Tüm uç noktalar için tek kesici Gönderme ve yoklama uç noktaları için ayrı kesiciler kullanın

SSS

Gönderme ve yoklama için ayrı devre kesiciler mi kullanmalıyım?

Evet, büyük ölçekli sistemler için. Yoklama hala çalışıyorken gönderim uç noktası başarısız olabilir (veya tam tersi). Ayrı kesiciler size daha hassas kontrol sağlar.

Devre açıkken ne yapmalıyım?

CAPTCHA görevini daha sonra kullanmak üzere sıraya koyun, bir yedek kullanıcı arayüzü gösterin veya işlemi atlayın. GörmekÇözüm Başarısız Olduğunda Zarif Bozulma.


CaptchaAI ile esnek CAPTCHA iş akışları oluşturun

API anahtarınızı şu adresten alın:captchaai.com.


İlgili kılavuzlar

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