Troubleshooting

Limites de solicitação simultânea CaptchaAI: diagnóstico e correções

ERROR_NO_SLOT_AVAILABLE não é um bug no seu código — é a CaptchaAI avisando que você está enviando mais tarefas ao mesmo tempo do que o seu plano permite processar. O erro costuma aparecer na pior hora: no meio de um lote grande, num pico de monitoramento de preços ou logo depois de escalar um scraper de 5 para 40 workers. A correção não é reduzir o volume de requisições, e sim controlar a concorrência. Este guia mostra os dois limites reais da API — tarefas simultâneas e taxa de requisições —, como diagnosticar qual deles você está atingindo, e quatro formas de resolver isso em Python sem estourar o plano contratado.


Diagnóstico rápido: qual limite você atingiu

O que aparece no seu log O que está acontecendo
ERROR_NO_SLOT_AVAILABLE Muitas tarefas ativas na CaptchaAI ao mesmo tempo
Resposta HTTP 429 Muitas requisições por segundo para o endpoint da API
Algumas tarefas terminam bem, outras falham Você está batendo no limite de forma intermitente
O tempo de resolução vai aumentando aos poucos A fila da sua conta está congestionada

Regra prática: ERROR_NO_SLOT_AVAILABLE é sobre concorrência — tarefas em voo ao mesmo tempo. HTTP 429 é sobre volume de chamadas por segundo, mesmo com uma única tarefa ativa. Correções diferentes para cada um.

Os dois limites da API da CaptchaAI

A CaptchaAI aplica dois limites de taxa independentes:

Tipo de limite O que ele controla Erro retornado
Tarefas simultâneas Quantas tarefas podem estar sendo resolvidas ao mesmo tempo ERROR_NO_SLOT_AVAILABLE
Taxa de requisições Quantas chamadas de API por segundo os endpoints de envio/consulta aceitam HTTP 429

O limite de tarefas simultâneas é definido pelo número de threads do seu plano. Verifique seu painel em captchaai.com para confirmar o limite atual antes de dimensionar workers.

Quantas threads cada plano inclui

Cada plano define um número fixo de threads simultâneas — sem cobrança por solve, sem limite diário:

Plano Threads simultâneas Preço mensal
BASIC 5 $15
STANDARD 15 $30
ADVANCE 50 $90
PREMIUM 100 $170
CORPORATE 150 $240
ENTERPRISE 200 $300
VIP-1 1000 $1,500
VIP-2 3000 $4,500
VIP-3 5000 $7,500

Exemplo: pico de tráfego em sa-east-1

Cenário comum entre equipes que monitoram preços de concorrentes: workers em sa-east-1 (São Paulo) para reduzir a latência até os sites acompanhados.

  • A equipe roda 5 threads no plano BASIC sem problema por semanas.
  • Um pico de demanda leva o time a escalar para 40 threads da noite para o dia, sem atualizar o plano.
  • O oitavo ou nono worker que entra no ar já recebe ERROR_NO_SLOT_AVAILABLE.
  • O código está correto — falta mais threads no plano, ou um semáforo que respeite o limite atual (Correção 1).

Correção 1: limite a concorrência com um semáforo

Um threading.Semaphore garante que seu próprio código nunca ultrapasse o limite do plano:

  • Nunca deixa mais de MAX_CONCURRENT tarefas em voo ao mesmo tempo.
  • Funciona mesmo com módulos diferentes chamando solve_captcha de pontos distintos.
  • Não elimina a necessidade de tratar ERROR_NO_SLOT_AVAILABLE — só reduz a frequência (ver Correção 2).
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")

Correção 2: trate ERROR_NO_SLOT_AVAILABLE com retentativa e backoff

Mesmo com semáforo, um pico de tráfego pode estourar o limite por alguns segundos. Em vez de deixar a tarefa falhar de vez, espere com backoff exponencial e tente de novo:

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")

Correção 3: organize o envio com uma fila de tarefas

Se você processa centenas de CAPTCHAs em lote, a fila resolve o problema em três passos:

  1. Enfileire todas as tarefas de uma vez, sem disparar requisições diretamente.
  2. Suba um número fixo de workers — o mesmo valor de MAX_CONCURRENT do semáforo.
  3. Deixe cada worker puxar da fila, resolver e gravar o resultado, um de cada vez.
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")

Correção 4: reduza a frequência de polling

Consultar o resultado a cada segundo desperdiça chamadas de API e, sozinho, já pode acionar o HTTP 429 — mesmo com poucas tarefas simultâneas:

Intervalo de polling Efeito
A cada 1 s Desperdiça chamadas; risco real de HTTP 429
A cada 5 s Recomendado para a maioria dos fluxos
Espera inicial de 15 s + polling a cada 5 s Melhor opção para tarefas com solve time mais alto
# 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)

Acompanhe quantas tarefas estão ativas em tempo real

Um contador simples ajuda a confirmar, em produção, se você está realmente perto do limite antes de ver o erro:

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
  • active_count perto do limite por longos períodos = plano subdimensionado; considere mais threads.
  • active_count baixo mas o erro aparece mesmo assim = outro processo ou máquina está consumindo threads da mesma conta (ver a próxima pergunta).

Perguntas frequentes

Aumentar MAX_CONCURRENT no código já resolve o ERROR_NO_SLOT_AVAILABLE?

Só se o novo valor ainda couber no seu plano. MAX_CONCURRENT deve refletir o número de threads contratado, não um valor arbitrário — subir esse número além do que o plano permite só troca um erro no seu código por um erro da API.

O limite de tarefas simultâneas é igual ao número de threads do meu plano?

Sim. Confira a tabela de threads por plano no início deste guia — ela mostra o número de threads de cada plano, do BASIC ao VIP-3. Cada thread aceita requisições ilimitadas dentro do mês — o limite é de concorrência, não de volume total de tarefas.

Rodar vários processos Python, cada um com seu próprio semáforo, também é limitado?

Sim. O limite vale por conta/chave de API, não por processo local. Distribuindo workers entre processos ou máquinas, a soma das concorrências precisa respeitar o limite do plano — centralize o controle (por exemplo, com um semáforo distribuído via Redis) em vez de configurar MAX_CONCURRENT isoladamente em cada processo.

Como aumento meu limite de tarefas simultâneas?

Atualize para um plano com mais threads ou fale com o suporte da CaptchaAI. Não existe forma de ultrapassar o limite do plano atual só ajustando o código.

Qual é a diferença entre ERROR_NO_SLOT_AVAILABLE e HTTP 429?

ERROR_NO_SLOT_AVAILABLE significa tarefas demais sendo resolvidas ao mesmo tempo. HTTP 429 significa requisições demais por segundo ao endpoint da API — inclusive polling. Os dois pedem a mesma resposta: reduzir a concorrência e aplicar backoff.


Ajuste sua concorrência na CaptchaAI

Verifique o limite de threads do seu plano e escale sem bater em ERROR_NO_SLOT_AVAILABLE — confira o painel em captchaai.com.


Guias relacionados

Os comentários estão desativados para este artigo.