Troubleshooting

Batas Request Concurrent CaptchaAI: Diagnosis dan Perbaikan

ERROR_NO_SLOT_AVAILABLE bukan tanda akun Anda bermasalah — itu CaptchaAI menolak task baru karena thread concurrent pada paket Anda sedang penuh semua. Begini cara mengenali batas mana yang sebenarnya Anda langgar, lalu memperbaikinya dengan semaphore, retry backoff, task queue, dan polling yang lebih hemat, sebelum buru-buru upgrade paket yang belum tentu perlu.

Aturan cepatnya: ERROR_NO_SLOT_AVAILABLE selalu soal jumlah thread yang terpakai bersamaan. HTTP 429 selalu soal kecepatan Anda memanggil API, termasuk saat polling. Dua masalah, dua perbaikan berbeda.


Dua Rate Limit CaptchaAI: Thread Concurrent vs Kecepatan Request

Batas task concurrent Anda mengikuti paket yang aktif, bukan angka tetap untuk semua akun — sama dengan jumlah thread pada paket itu. Batas request rate berlaku terpisah, per akun, tidak peduli paketnya apa:

Jenis batas Yang dikontrol Error yang muncul
Task concurrent Jumlah task yang sedang diselesaikan secara bersamaan ERROR_NO_SLOT_AVAILABLE
Request rate Jumlah panggilan API per detik ke endpoint submit/poll HTTP 429

Satu thread menampung satu task yang sedang diselesaikan; begitu task selesai, thread langsung bebas dipakai task berikutnya.


Kenali Dulu Gejalanya, Baru Cari Perbaikannya

Empat pola gejala berikut mencakup hampir semua tiket yang masuk soal batas concurrent:

Yang terlihat Kemungkinan penyebab
Sebagian task berhasil, sebagian gagal di waktu bersamaan Anda sesekali menyentuh batas thread concurrent
Waktu solve makin lama padahal jumlah task tetap Antrean menumpuk di sisi akun Anda
ERROR_NO_SLOT_AVAILABLE hanya muncul saat jam sibuk Proses lain di akun yang sama ikut memakai thread
HTTP 429 muncul walau task concurrent Anda sedikit Loop polling terlalu rapat, bukan soal thread

Berapa Thread yang Anda Punya? Cek Dulu Sebelum Ubah Kode

Untuk tim yang baru mengukur kebutuhan concurrency-nya, titik awal yang wajar:

  • BASIC ($15/bulan, 5 thread) — cukup untuk uji coba atau volume kecil.
  • STANDARD ($30/bulan, 15 thread) — titik awal umum untuk tim scraping atau otomatisasi lepasan yang sudah jalan di produksi skala kecil.
  • ADVANCE ($90/bulan, 50 thread) — untuk beban paralel yang lebih berat, misalnya price-monitoring di puluhan domain sekaligus.

Kalau worker Anda tersebar lintas region — misalnya browser headless jalan di AWS ap-southeast-1 (Singapura) sementara server yang mengirim task ada di ap-southeast-3 (Jakarta) — latency jaringan menambah waktu tiap task menahan thread-nya. Artinya jumlah task paralel yang aman biasanya sedikit di bawah jumlah thread nominal Anda, bukan persis sama. Cek dashboard di captchaai.com untuk melihat alokasi thread paket Anda saat ini.


Perbaikan 1: Batasi Concurrency dengan Semaphore

Jangan biarkan kode Anda menembak task sebanyak-banyaknya tanpa kendali. Pasang semaphore yang menahan jumlah task paralel tepat di bawah batas thread akun Anda:

import requests
import time
import threading

API_KEY = "YOUR_API_KEY"
MAX_CONCURRENT = 20  # Stay below your account limit

semaphore = threading.Semaphore(MAX_CONCURRENT)


def solve_captcha(params):
    """Solve a CAPTCHA with concurrency control."""
    with semaphore:
        params["key"] = API_KEY
        params["json"] = 1

        submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()
        if submit.get("status") != 1:
            raise RuntimeError(f"Submit: {submit.get('request')}")

        task_id = submit["request"]
        time.sleep(10)

        for _ in range(30):
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": API_KEY, "action": "get", "id": task_id, "json": 1
            }).json()
            if result.get("status") == 1:
                return result["request"]
            if result.get("request") != "CAPCHA_NOT_READY":
                raise RuntimeError(f"Solve: {result['request']}")
            time.sleep(5)
        raise TimeoutError("Timed out")

Kenapa MAX_CONCURRENT Perlu di Bawah Batas Nyata, Bukan Persis Sama

MAX_CONCURRENT di sini sengaja diset di bawah batas thread nyata Anda, bukan persis sama dengan angka di dashboard. Sisakan sedikit ruang untuk proses lain yang mungkin berjalan bersamaan di akun yang sama — dashboard, cron job lain, atau worker kedua yang lupa Anda matikan.


Perbaikan 2: Retry Otomatis Saat ERROR_NO_SLOT_AVAILABLE

Semaphore mengatur sisi kode Anda, tapi thread di akun bisa saja penuh sesaat karena proses lain. Daripada task langsung gagal, retry dengan jeda yang meningkat eksponensial (exponential backoff):

def submit_with_retry(params, max_retries=5):
    """Submit with automatic retry for slot errors."""
    params["key"] = API_KEY
    params["json"] = 1

    for attempt in range(max_retries):
        resp = requests.post("https://ocr.captchaai.com/in.php", data=params).json()

        if resp.get("status") == 1:
            return resp["request"]

        error = resp.get("request", "")
        if error == "ERROR_NO_SLOT_AVAILABLE":
            wait = 2 ** attempt  # Exponential backoff: 1, 2, 4, 8, 16 seconds
            print(f"No slot available, retrying in {wait}s (attempt {attempt + 1})")
            time.sleep(wait)
            continue
        else:
            raise RuntimeError(f"Submit error: {error}")

    raise RuntimeError("Max retries exceeded — no slots available")

Yang perlu Anda perhatikan dari pola ini:

  • Menyerap lonjakan singkat tanpa membanjiri API dengan percobaan ulang yang justru memperparah antrean.
  • Jeda naik otomatis tiap percobaan (1, 2, 4, 8, 16 detik) — bukan interval tetap.
  • Error selain ERROR_NO_SLOT_AVAILABLE langsung dilempar, tidak ikut di-retry buta.

Perbaikan 3: Pakai Task Queue, Jangan Kirim Semua Sekaligus

Kalau jumlah task yang harus diproses besar, menembakkannya semua ke API dalam satu waktu hanya memindahkan masalah dari kode Anda ke error CaptchaAI. Antrekan task, lalu proses dengan worker sejumlah MAX_CONCURRENT:

from queue import Queue
from threading import Thread

task_queue = Queue()
results = {}


def worker():
    while True:
        task_id_local, params = task_queue.get()
        try:
            token = solve_captcha(params)
            results[task_id_local] = {"status": "ok", "token": token}
        except Exception as e:
            results[task_id_local] = {"status": "error", "message": str(e)}
        finally:
            task_queue.task_done()


# Start worker threads (limited by semaphore)
for _ in range(MAX_CONCURRENT):
    t = Thread(target=worker, daemon=True)
    t.start()

# Add tasks to queue
captcha_tasks = [
    {"method": "userrecaptcha", "googlekey": "KEY1", "pageurl": "https://site1.com"},
    {"method": "userrecaptcha", "googlekey": "KEY2", "pageurl": "https://site2.com"},
    # ... more tasks
]

for i, params in enumerate(captcha_tasks):
    task_queue.put((i, params))

task_queue.join()
print(f"Completed: {len(results)} tasks")

Pola ini juga memudahkan Anda melacak task mana yang gagal, tanpa kehilangan hasil task lain yang sudah selesai duluan.


Perbaikan 4: Kurangi Frekuensi Polling

Polling yang terlalu rapat membuang panggilan API dan bisa memicu HTTP 429 sendiri — masalah yang terpisah dari batas thread concurrent:

# WRONG — polling every 1 second
time.sleep(1)

# CORRECT — poll every 5 seconds
time.sleep(5)

# BETTER — wait longer on initial delay, then poll
time.sleep(15)  # Initial wait
for _ in range(20):
    # ... poll
    time.sleep(5)

Aturan Praktis Interval Polling

Beri jeda awal sebelum polling pertama — solve jarang selesai dalam hitungan di bawah beberapa detik — lalu poll setiap 5 detik, bukan setiap detik. Ini mengurangi jumlah panggilan res.php per task secara signifikan tanpa membuat Anda menunggu lebih lama untuk hasil yang sebenarnya belum siap.


Pantau Jumlah Task Aktif Secara Real-Time

Sebelum menyalahkan batas akun, pastikan dulu kode Anda sendiri tidak diam-diam membuka lebih banyak task paralel dari yang Anda kira:

active_count = 0
lock = threading.Lock()

def track_solve(params):
    global active_count
    with lock:
        active_count += 1
        print(f"Active tasks: {active_count}/{MAX_CONCURRENT}")
    try:
        return solve_captcha(params)
    finally:
        with lock:
            active_count -= 1

Log ini juga berguna untuk mencari MAX_CONCURRENT yang pas: naikkan pelan-pelan sampai ERROR_NO_SLOT_AVAILABLE mulai muncul, lalu turunkan sedikit dari titik itu.


Pertanyaan Umum

Ringkasan sebelum masuk detail — perbaikan mana untuk gejala mana:

Gejala Perbaikan yang relevan
ERROR_NO_SLOT_AVAILABLE terus-menerus Perbaikan 1 (semaphore) + Perbaikan 3 (task queue)
ERROR_NO_SLOT_AVAILABLE sesekali Perbaikan 2 (retry backoff)
HTTP 429 saat polling Perbaikan 4 (kurangi frekuensi polling)

Kenapa ERROR_NO_SLOT_AVAILABLE muncul padahal traffic saya tidak terlalu besar?

Penyebab paling sering: task lama tidak pernah "dilepas". Worker yang crash sebelum polling selesai bisa meninggalkan thread tertahan sampai timeout server. Cek apakah semua task Anda benar-benar mencapai status selesai atau timeout, bukan menggantung tanpa penanganan.

Berapa MAX_CONCURRENT yang aman untuk paket BASIC atau STANDARD saya?

Sebagai titik awal, set MAX_CONCURRENT sedikit di bawah jumlah thread paket Anda, lalu naikkan bertahap sambil memantau log task aktif dari bagian sebelumnya:

  • BASIC (5 thread) → mulai dari MAX_CONCURRENT = 4
  • STANDARD (15 thread) → mulai dari MAX_CONCURRENT = 12
  • ADVANCE (50 thread) → mulai dari MAX_CONCURRENT = 40

Apakah polling res.php ikut dihitung ke rate limit request?

Ya. Setiap request res.php dihitung sebagai satu panggilan API, sama seperti in.php. Poll setiap 5 detik, bukan setiap 1 detik, supaya tidak memicu HTTP 429 secara terpisah dari batas thread concurrent Anda.

Task saya sebagian berhasil dan sebagian gagal dengan error slot penuh — apakah ini wajar?

Ya, ini pola khas menyentuh batas secara sesekali, bukan terus-menerus. Task yang terkirim saat thread masih tersedia berhasil; task yang terkirim tepat saat semua thread penuh gagal. Retry dengan backoff (Perbaikan 2) menyelesaikan sebagian besar kasus ini tanpa perlu upgrade paket.

Bagaimana cara menambah batas thread concurrent saya?

Upgrade ke paket dengan alokasi thread lebih besar — lihat perbandingan paket di captchaai.com. Sebelum menambah biaya bulanan, cek dua hal dulu:

  • Apakah lonjakan task Anda musiman, atau memang konsisten naik terus
  • Apakah semaphore dan task queue di atas sudah benar-benar menyerap lonjakannya

Pilih Paket Thread CaptchaAI Sesuai Volume Concurrent Anda

Kalau ERROR_NO_SLOT_AVAILABLE tetap muncul setelah semaphore, retry, dan task queue terpasang rapi, itu sinyal jelas: paket Anda memang kekurangan thread, bukan masalah kode. Bandingkan paket dan alokasi thread di captchaai.com.


Bacaan Lanjutan

Komentar dinonaktifkan untuk artikel ini.