DevOps & Scaling

Arsitektur Solve CAPTCHA Multi-Region dengan CaptchaAI

Anda butuh arsitektur multi-region begitu target scraping tersebar di banyak negara dan satu titik kegagalan mulai terasa mahal. Menempatkan worker di dekat situs target — misalnya di AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta) untuk target Asia Tenggara, dan di eu-west-1 untuk target Eropa — memangkas waktu bolak-balik request dan menjaga throughput tetap jalan saat satu region bermasalah. Sebaliknya, kalau target Anda hanya di satu negara dan volume masih di bawah seribu task per jam, satu region sudah cukup dan multi-region hanya menambah biaya operasional.

Artikel ini menunjukkan pola konkret: kapan multi-region layak, cara routing task ke region terdekat, cara failover saat satu region tumbang, dan cara memantau kesehatan tiap region. CaptchaAI sendiri memakai satu kunci API global dengan penagihan berbasis thread, jadi seluruh biaya multi-region ada di sisi infrastruktur Anda, bukan di sisi solver.

Sekilas arsitektur

                    [Task Router]
                    (Route53 / Load Balancer)
                    ↙        ↓        ↘
        [US-East]      [EU-West]     [AP-Southeast]
        Workers        Workers        Workers
            ↓              ↓              ↓
        [CaptchaAI API] ← shared API key
            ↓              ↓              ↓
        [Central DB / Queue]
        (Results aggregation)

Arsitektur ini punya tiga lapis yang jelas:

  • Router task memutuskan region tujuan tiap task berdasarkan lokasi situs target.
  • Fleet worker per region menjalankan proses penyelesaian secara mandiri di tiap lokasi.
  • Penyimpanan pusat mengumpulkan seluruh hasil untuk agregasi dan pelaporan.

Setiap region menjalankan worker mandiri. Semuanya memakai kunci API CaptchaAI yang sama dan mendorong hasil ke satu penyimpanan pusat untuk agregasi.

Menempatkan worker di tiap region

Worker Python yang sadar region

import os
import time
import requests

API_KEY = os.environ["CAPTCHAAI_API_KEY"]
REGION = os.environ.get("WORKER_REGION", "us-east-1")
RESULT_QUEUE_URL = os.environ["RESULT_QUEUE_URL"]


def solve_captcha(task):
    """Solve CAPTCHA and tag with region metadata."""
    start = time.time()

    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": task["method"],
        "googlekey": task["sitekey"],
        "pageurl": task["pageurl"],
        "json": 1
    })
    data = resp.json()

    if data.get("status") != 1:
        return {
            "task_id": task["task_id"],
            "error": data.get("request"),
            "region": REGION
        }

    captcha_id = data["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": captcha_id, "json": 1
        }).json()

        if result.get("status") == 1:
            return {
                "task_id": task["task_id"],
                "solution": result["request"],
                "region": REGION,
                "duration": time.time() - start,
                "api_latency_ms": round((time.time() - start) * 1000)
            }
        if result.get("request") != "CAPCHA_NOT_READY":
            return {
                "task_id": task["task_id"],
                "error": result.get("request"),
                "region": REGION
            }

    return {"task_id": task["task_id"], "error": "TIMEOUT", "region": REGION}

Router task

Arahkan setiap task ke region yang paling dekat dengan situs target. Pemetaan sederhana berbasis TLD sudah cukup untuk memulai, lalu perhalus aturannya seiring pola trafik Anda terbaca:

from urllib.parse import urlparse

# Region mapping by target site TLD/domain
REGION_MAP = {
    ".co.uk": "eu-west-1",
    ".de": "eu-central-1",
    ".fr": "eu-west-3",
    ".jp": "ap-northeast-1",
    ".com.au": "ap-southeast-2",
    ".com": "us-east-1",  # Default
}

REGION_QUEUES = {
    "us-east-1": "sqs://captcha-tasks-us-east",
    "eu-west-1": "sqs://captcha-tasks-eu-west",
    "ap-southeast-1": "sqs://captcha-tasks-ap-southeast",
}


def route_task(task):
    """Route task to the closest regional queue."""
    domain = urlparse(task["pageurl"]).netloc

    target_region = "us-east-1"  # Default
    for suffix, region in REGION_MAP.items():
        if domain.endswith(suffix):
            target_region = region
            break

    queue = REGION_QUEUES.get(target_region, REGION_QUEUES["us-east-1"])
    send_to_queue(queue, task)
    return target_region

Menyiapkan infrastruktur

Modelkan region sebagai satu variabel dan biarkan Terraform men-deploy fleet identik ke tiap lokasi. Pola ini menjaga tiga hal tetap konsisten di semua region:

  • Satu antrean task masuk (SQS) per region.
  • Satu antrean hasil pusat yang dibagi semua region.
  • Satu secret kunci API yang direferensikan tiap fleet.

Kerangka Terraform

# Define regions
variable "regions" {
  default = ["us-east-1", "eu-west-1", "ap-southeast-1"]
}

# Deploy worker fleet per region
module "captcha_workers" {
  for_each = toset(var.regions)
  source   = "./modules/captcha-worker"

  region              = each.key
  worker_count        = var.workers_per_region
  api_key_secret_arn  = aws_secretsmanager_secret.captchaai_key.arn
  task_queue_arn      = aws_sqs_queue.tasks[each.key].arn
  result_queue_arn    = aws_sqs_queue.results.arn
}

# SQS queue per region for task intake
resource "aws_sqs_queue" "tasks" {
  for_each = toset(var.regions)
  name     = "captcha-tasks-${each.key}"
}

# Central result queue
resource "aws_sqs_queue" "results" {
  name = "captcha-results-central"
}

Docker Compose untuk simulasi multi-region lokal

Uji perilaku multi-region secara lokal dengan tiga service worker yang berbagi satu Redis:

version: "3.8"
services:
  worker-us:
    build: ./worker
    environment:

      - CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
      - WORKER_REGION=us-east-1
      - TASK_QUEUE=redis://redis:6379/0
    depends_on:

      - redis

  worker-eu:
    build: ./worker
    environment:

      - CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
      - WORKER_REGION=eu-west-1
      - TASK_QUEUE=redis://redis:6379/1

  worker-ap:
    build: ./worker
    environment:

      - CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
      - WORKER_REGION=ap-southeast-1
      - TASK_QUEUE=redis://redis:6379/2

  redis:
    image: redis:7-alpine

Memantau kesehatan tiap region

Tanpa observabilitas, Anda tidak akan tahu satu region melambat sampai task mulai menumpuk. Cek endpoint kesehatan tiap region secara berkala dan catat tiga sinyal yang nantinya memicu failover:

  • Latensi respons endpoint kesehatan.
  • Jumlah worker aktif di region tersebut.
  • Kedalaman antrean yang menunggu diproses.

Health check dengan Node.js

const axios = require("axios");

const REGIONS = ["us-east-1", "eu-west-1", "ap-southeast-1"];

async function checkRegionHealth() {
  const health = {};

  for (const region of REGIONS) {
    const endpoint = `https://${region}.workers.example.com/health`;
    try {
      const start = Date.now();
      const resp = await axios.get(endpoint, { timeout: 5000 });
      health[region] = {
        status: "healthy",
        latencyMs: Date.now() - start,
        activeWorkers: resp.data.activeWorkers,
        queueDepth: resp.data.queueDepth,
      };
    } catch (err) {
      health[region] = { status: "unhealthy", error: err.message };
    }
  }

  return health;
}

// Periodic health check
setInterval(async () => {
  const health = await checkRegionHealth();
  console.table(health);
}, 60000);

Strategi failover

Saat sebuah region tumbang atau gagal melewati gerbang kesehatan, alihkan task-nya ke region sehat dengan antrean paling ringan. Logikanya berjalan dalam tiga langkah:

  1. Kumpulkan daftar region yang masih sehat.
  2. Untuk tiap region bermasalah, pilih tujuan sehat dengan kedalaman antrean paling kecil.
  3. Catat pengalihan tersebut agar bisa diaudit setelah insiden.

Jika tidak ada satu pun region yang sehat, hentikan proses dan picu peringatan alih-alih memaksakan pengalihan.

def failover_check(region_health):
    """Redirect tasks from unhealthy regions."""
    healthy_regions = [
        r for r, h in region_health.items()
        if h["status"] == "healthy"
    ]

    if not healthy_regions:
        raise RuntimeError("All regions unhealthy")

    redirects = {}
    for region, health in region_health.items():
        if health["status"] == "unhealthy":
            # Pick the healthy region with lowest queue depth
            target = min(
                healthy_regions,
                key=lambda r: region_health[r].get("queue_depth", 0)
            )
            redirects[region] = target
            print(f"Failover: {region} → {target}")

    return redirects

Aturan menjalankan failover dengan rapi

Failover yang buruk justru menciptakan masalah baru. Tiga aturan operasional yang sebaiknya Anda pegang:

  • Hentikan pengiriman task baru ke region yang terdegradasi begitu latensi, tingkat kesalahan, atau sinyal jaringan melewati ambang kebijakan Anda.
  • Selesaikan pekerjaan yang sedang berjalan secara sengaja, alih-alih memindahkan seluruh antrean dan sesi secara mendadak.
  • Kembalikan trafik ke region tersebut hanya setelah ia lolos gerbang kesehatan yang sama seperti sebelum failover.

Kapan multi-region benar-benar sepadan

Setelah melihat mekanismenya, mundur sejenak: multi-region bukan default. Pakai tabel ini untuk memutuskan sebelum menambah kompleksitas infrastruktur:

Situasi Satu region Multi-region
Target hanya di satu negara Cukup Berlebihan
Target tersebar global Latensi tambahan 100–300 ms Latensi lokal per region
Butuh uptime 99,9% Sulit dijaga Redundansi alami
Kepatuhan residensi data Sulit dipenuhi Proses di region setempat
< 1.000 task/jam Baik Kompleksitas yang tidak perlu
> 10.000 task/jam Mentok batas skala Beban terdistribusi

Untuk tim di Indonesia, kasus yang paling sering muncul adalah campuran: sebagian target di Asia Tenggara, sebagian di Amerika dan Eropa. Di sinilah routing per region mulai membayar dirinya sendiri. Naikkan ke multi-region jika minimal satu pemicu ini terpenuhi:

  1. Target tersebar di beberapa benua dan latensi mulai terasa.
  2. Ada target uptime formal yang mustahil dipenuhi oleh satu region.
  3. Ada kewajiban residensi data yang menuntut pemrosesan di yurisdiksi tertentu.

Merinci biaya multi-region

Biaya multi-region datang dari infrastruktur, bukan dari solver. CaptchaAI menagih berbasis thread dengan tarif yang sama di mana pun worker Anda berjalan — mulai dari paket BASIC $15 hingga tier VIP untuk volume besar — jadi menyebar worker ke tiga region tidak menambah premi apa pun di sisi API.

Komponen Faktor biaya Cara menekan
Instance worker Komputasi per region Auto-scale ke nol saat idle
Transfer data antar region $0.02/GB antar region Perkecil ukuran payload hasil
Antrean SQS Harga per request Kirim pesan secara batch
API CaptchaAI Tarif sama di semua region Tanpa premi multi-region

Untuk tim yang sensitif terhadap biaya — banyak agensi scraping dan tim data startup di Indonesia — penagihan flat berbasis thread justru menjadikan multi-region mudah dianggarkan: kapasitas solve tidak berubah harganya saat Anda menambah region.


Pertanyaan umum

Region mana yang sebaiknya saya pilih untuk target di Asia Tenggara?

Tempatkan worker di ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta) agar dekat dengan situs target di kawasan ini. Untuk cakupan campuran, tambahkan satu region Eropa dan satu region Amerika, lalu biarkan router mengarahkan tiap task ke yang paling dekat.

Apakah menambah region membuat tagihan CaptchaAI naik?

Tidak. CaptchaAI menagih berbasis thread dengan tarif yang sama di mana pun worker berjalan, jadi jumlah region tidak mengubah biaya solve. Yang bertambah hanyalah biaya infrastruktur Anda sendiri: instance, transfer data antar region, dan antrean.

Bagaimana multi-region membantu kepatuhan residensi data?

Dengan memproses task di region setempat, Anda bisa menjaga data agar tetap berada di yurisdiksi yang diizinkan. Ini relevan dengan UU Pelindungan Data Pribadi (UU 27/2022); tetap batasi pemrosesan hanya pada data yang memang berhak Anda olah. Ini bukan nasihat hukum.

Kapan sebaiknya saya tetap pakai satu region saja?

Jika target Anda hanya di satu negara dan volume di bawah 1.000 task per jam, satu region lebih sederhana dan lebih murah. Naik ke multi-region saat target mulai tersebar global atau saat Anda butuh redundansi untuk memenuhi target uptime.

Mengatasi masalah umum

Masalah Penyebab Perbaikan
Satu region konsisten lebih lambat Jarak ke server CaptchaAI Bandingkan latensi dasar; bisa jadi memang wajar
Semua task masuk ke satu region Aturan routing berbasis domain terlalu luas Tambahkan aturan routing yang lebih terperinci
Failover tidak terpicu Endpoint health check tidak merespons Pastikan endpoint kesehatan berada di jalur terpisah dari logika worker
Saldo kunci API terkuras lebih cepat Semua region memakai satu kunci Wajar — pantau penggunaan agregat

Artikel terkait

Langkah selanjutnya

Sebarkan worker CaptchaAI di beberapa region — ambil kunci API Anda lalu bangun infrastruktur penyelesaian CAPTCHA yang tahan gangguan.

Panduan terkait:

Komentar dinonaktifkan untuk artikel ini.