Reference

CaptchaAI em produção: guia de gerenciamento de configuração

Qual variável ganha quando o .env, o arquivo YAML e o valor padrão do código dizem coisas diferentes? A resposta curta: a variável de ambiente sempre vence — e é em torno dessa regra que qualquer configuração de produção da CaptchaAI deveria ser desenhada.

Uma chave de API fixa no código funciona enquanto o projeto roda só na sua máquina. Quando a mesma integração passa a atender staging, produção e uma região secundária, esses valores precisam mudar sem novo deploy — e a chave sai do repositório.

Neste guia:

  • hierarquia entre variável de ambiente, arquivo e padrão no código;
  • referência completa de cada variável CAPTCHAAI_*;
  • carregadores em Python e Node.js;
  • onde guardar segredos e como versionar um YAML por ambiente;
  • os erros de configuração mais comuns.

Qual configuração vale: variável de ambiente, arquivo ou padrão do código?

Priority (highest → lowest):

1. Environment variables     ← deployment-specific overrides
2. Config file (YAML/JSON)   ← version-controlled defaults
3. Application defaults      ← fallback values in code

Na prática: a variável de ambiente sobrescreve o arquivo de configuração, que sobrescreve os padrões embutidos no código. Se o serviço aceitar uma flag de linha de comando, coloque-a acima das variáveis de ambiente — o mesmo princípio se aplica: quem está mais perto do operador no momento do deploy tem prioridade.

Referência completa de configuração: todas as variáveis de ambiente da CaptchaAI

Parâmetro Variável de ambiente Padrão Descrição
Chave de API CAPTCHAAI_API_KEY - Obrigatório. Sua chave de API da CaptchaAI
Submit URL CAPTCHAAI_SUBMIT_URL https://ocr.captchaai.com/in.php Endpoint de envio da tarefa
Poll URL CAPTCHAAI_POLL_URL https://ocr.captchaai.com/res.php Endpoint de polling do resultado
Intervalo de polling CAPTCHAAI_POLL_INTERVAL 5 Segundos entre tentativas de consulta
Máximo de tentativas de polling CAPTCHAAI_MAX_POLLS 60 Tentativas de consulta antes do tempo limite
Concorrência CAPTCHAAI_CONCURRENCY 10 Máximo de tarefas CAPTCHA em paralelo
Tempo limite CAPTCHAAI_TIMEOUT 300 Tempo limite geral, em segundos
Proxy CAPTCHAAI_PROXY - URL do proxy usado na resolução do CAPTCHA
URL de callback CAPTCHAAI_CALLBACK_URL - URL do webhook para resultados assíncronos
Retentativas CAPTCHAAI_RETRIES 3 Novas tentativas em falhas transitórias
Nível de log CAPTCHAAI_LOG_LEVEL info Verbosidade dos logs

São os mesmos nomes de variável usados nos carregadores abaixo (Python e Node.js) e nos arquivos YAML por ambiente mais adiante.

Carregando a configuração em Python e Node.js

Os dois carregadores abaixo implementam a mesma hierarquia: leem o arquivo de configuração, sobrescrevem com as variáveis de ambiente e validam antes de devolver o objeto pronto.

Python

import os
import yaml
from dataclasses import dataclass, field
from pathlib import Path


@dataclass
class CaptchaAIConfig:
    api_key: str = ""
    submit_url: str = "https://ocr.captchaai.com/in.php"
    poll_url: str = "https://ocr.captchaai.com/res.php"
    poll_interval: int = 5
    max_polls: int = 60
    concurrency: int = 10
    timeout: int = 300
    proxy: str = ""
    callback_url: str = ""
    retries: int = 3
    log_level: str = "info"

    @classmethod
    def load(cls, config_path=None):
        """Load config: env vars override file, which overrides defaults."""
        config = cls()

        # Layer 2: Config file
        if config_path and Path(config_path).exists():
            with open(config_path) as f:
                file_config = yaml.safe_load(f) or {}
            for key, value in file_config.items():
                if hasattr(config, key):
                    setattr(config, key, value)

        # Layer 1: Environment variables (highest priority)
        env_map = {
            "CAPTCHAAI_API_KEY": "api_key",
            "CAPTCHAAI_SUBMIT_URL": "submit_url",
            "CAPTCHAAI_POLL_URL": "poll_url",
            "CAPTCHAAI_POLL_INTERVAL": "poll_interval",
            "CAPTCHAAI_MAX_POLLS": "max_polls",
            "CAPTCHAAI_CONCURRENCY": "concurrency",
            "CAPTCHAAI_TIMEOUT": "timeout",
            "CAPTCHAAI_PROXY": "proxy",
            "CAPTCHAAI_CALLBACK_URL": "callback_url",
            "CAPTCHAAI_RETRIES": "retries",
            "CAPTCHAAI_LOG_LEVEL": "log_level",
        }

        for env_key, attr_name in env_map.items():
            value = os.environ.get(env_key)
            if value is not None:
                # Cast to correct type
                current = getattr(config, attr_name)
                if isinstance(current, int):
                    value = int(value)
                setattr(config, attr_name, value)

        config.validate()
        return config

    def validate(self):
        if not self.api_key:
            raise ValueError("CAPTCHAAI_API_KEY is required")
        if self.poll_interval < 1:
            raise ValueError("poll_interval must be >= 1")
        if self.concurrency < 1:
            raise ValueError("concurrency must be >= 1")


# Usage
config = CaptchaAIConfig.load("config/captchaai.yaml")
print(f"Concurrency: {config.concurrency}, Timeout: {config.timeout}s")

JavaScript

const fs = require("fs");
const yaml = require("js-yaml");
const path = require("path");

class CaptchaAIConfig {
  static defaults = {
    apiKey: "",
    submitUrl: "https://ocr.captchaai.com/in.php",
    pollUrl: "https://ocr.captchaai.com/res.php",
    pollInterval: 5,
    maxPolls: 60,
    concurrency: 10,
    timeout: 300,
    proxy: "",
    callbackUrl: "",
    retries: 3,
    logLevel: "info",
  };

  static envMap = {
    CAPTCHAAI_API_KEY: "apiKey",
    CAPTCHAAI_SUBMIT_URL: "submitUrl",
    CAPTCHAAI_POLL_URL: "pollUrl",
    CAPTCHAAI_POLL_INTERVAL: { key: "pollInterval", type: "int" },
    CAPTCHAAI_MAX_POLLS: { key: "maxPolls", type: "int" },
    CAPTCHAAI_CONCURRENCY: { key: "concurrency", type: "int" },
    CAPTCHAAI_TIMEOUT: { key: "timeout", type: "int" },
    CAPTCHAAI_PROXY: "proxy",
    CAPTCHAAI_CALLBACK_URL: "callbackUrl",
    CAPTCHAAI_RETRIES: { key: "retries", type: "int" },
    CAPTCHAAI_LOG_LEVEL: "logLevel",
  };

  static load(configPath = null) {
    let config = { ...CaptchaAIConfig.defaults };

    // Layer 2: Config file
    if (configPath && fs.existsSync(configPath)) {
      const ext = path.extname(configPath);
      const raw = fs.readFileSync(configPath, "utf8");
      const fileConfig = ext === ".json" ? JSON.parse(raw) : yaml.load(raw);
      config = { ...config, ...fileConfig };
    }

    // Layer 1: Environment variables
    for (const [envKey, mapping] of Object.entries(CaptchaAIConfig.envMap)) {
      const value = process.env[envKey];
      if (value !== undefined) {
        const attrKey = typeof mapping === "string" ? mapping : mapping.key;
        const type = typeof mapping === "string" ? "string" : mapping.type;
        config[attrKey] = type === "int" ? parseInt(value, 10) : value;
      }
    }

    CaptchaAIConfig.validate(config);
    return config;
  }

  static validate(config) {
    if (!config.apiKey) throw new Error("CAPTCHAAI_API_KEY is required");
    if (config.pollInterval < 1) throw new Error("pollInterval must be >= 1");
    if (config.concurrency < 1) throw new Error("concurrency must be >= 1");
  }
}

// Usage
const config = CaptchaAIConfig.load("config/captchaai.yaml");
console.log(`Concurrency: ${config.concurrency}, Timeout: ${config.timeout}s`);

Um arquivo de configuração por ambiente: base, produção e staging

Em vez de um único arquivo cheio de if ambiente == "produção", mantenha um arquivo base com os valores conservadores e um arquivo por ambiente que só sobrescreve o que muda — mais fácil de revisar e mais difícil de subir staging com config de produção por engano.

Base (todos os ambientes)

# config/captchaai.yaml — base
api_key: ""  # Always set via env var
concurrency: 5
poll_interval: 5
retries: 3
log_level: info

Produção

# config/captchaai.production.yaml
concurrency: 20
poll_interval: 3
timeout: 180
log_level: warning

Staging

# config/captchaai.staging.yaml
concurrency: 3
poll_interval: 5
timeout: 300
log_level: debug

Em produção o poll_interval cai para 3 s e a concurrency sobe para 20. Se os workers rodam em sa-east-1 (São Paulo), meça o RTT real até os endpoints da CaptchaAI antes de copiar esses valores.

Gerenciamento de segredos: onde guardar a chave de API

Regra única, sem exceção:

  • nunca guarde a chave de API em arquivo de configuração versionado;
  • nunca faça commit dela em controle de origem, nem em um branch privado.
Método Ideal para Exemplo
Variáveis de ambiente Contêineres, CI/CD export CAPTCHAAI_API_KEY=abc123
AWS Secrets Manager Infraestrutura AWS Busca na inicialização; rotação automática
HashiCorp Vault Múltiplas nuvens, on-premises Segredos dinâmicos com TTL
Docker secrets Docker Swarm / Docker Compose Montado em /run/secrets/
Arquivo .env (só em dev) Desenvolvimento local Biblioteca dotenv; adicione ao .gitignore

Exemplo com Docker Compose

services:
  captcha-worker:
    image: captcha-worker:latest
    environment:

      - CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
      - CAPTCHAAI_CONCURRENCY=15
      - CAPTCHAAI_LOG_LEVEL=warning
    env_file:

      - .env.production

Nota de conformidade: isso também é LGPD, não só segurança. Se o log de configuração ou de requisições grava a chave de API (ou dado que identifique um usuário) em texto puro, mascare o valor no output — CAPTCHAAI_API_KEY=abc1*** — antes de enviar para qualquer sistema de observabilidade.

Feature flags: mude o comportamento sem reimplantar

class FeatureFlags:
    def __init__(self):
        self.flags = {
            "use_callback": os.environ.get("FF_USE_CALLBACK", "false") == "true",
            "enable_proxy": os.environ.get("FF_ENABLE_PROXY", "true") == "true",
            "max_concurrent": int(os.environ.get("FF_MAX_CONCURRENT", "10")),
        }

    def is_enabled(self, flag):
        return self.flags.get(flag, False)

    def get(self, flag, default=None):
        return self.flags.get(flag, default)

Isso resolve um problema comum: ligar um recurso novo (por exemplo, callback em vez de polling) sem esperar o próximo deploy — trocar FF_USE_CALLBACK para true no orquestrador já basta.

Erros comuns de configuração e como resolver

A maioria dos chamados cai em duas categorias: não carrega ou carrega o valor errado.

Problema Causa provável Como resolver
Chave de API não carrega Variável de ambiente ausente ou nome digitado errado Rode echo $CAPTCHAAI_API_KEY e confira a grafia exata
Arquivo de configuração é ignorado Caminho incorreto ou biblioteca YAML não instalada Confirme que o arquivo existe; instale pyyaml ou js-yaml
Produção sobe com valores de desenvolvimento O override específico do ambiente não foi aplicado Confira a ordem de precedência das env vars e o valor de NODE_ENV / APP_ENV
Segredos aparecem nos logs O dump de configuração inclui a chave de API sem máscara Mascare os campos sensíveis antes de gravar qualquer log

Perguntas frequentes

Qual valor vence se eu definir a mesma chave na variável de ambiente e no YAML?

A variável de ambiente. É a camada mais próxima do deploy, então sobrescreve o arquivo de configuração e os padrões do código.

Posso usar o arquivo .env direto em produção?

Não é recomendado. .env é prático em dev, mas em produção prefira variáveis injetadas pelo orquestrador (Kubernetes, ECS) ou um gerenciador de segredos como AWS Secrets Manager ou HashiCorp Vault.

Como evito que a chave de API vaze nos logs?

Mascare o valor antes de logar qualquer dump de configuração (mostre só os últimos caracteres, ***c123) e confira se o middleware de log não grava o header Authorization por padrão.

Preciso reiniciar o worker depois de mudar a concorrência?

Não, se o serviço ler a configuração a cada lote de tarefas, não só na inicialização. Basta atualizar CAPTCHAAI_CONCURRENCY e enviar um sinal de recarga.

YAML ou JSON: qual formato usar no arquivo de configuração?

YAML para arquivos editados por humanos — aceita comentários. JSON quando a configuração é gerada por outro sistema ou você quer uma análise mais rígida.

Artigos relacionados

Próximas etapas

Leve sua configuração para produção: gere uma chave de API da CaptchaAI e monte os três arquivos YAML a partir dos modelos deste guia.

Guias relacionados:

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