Déployez vos workers là où sont vos sites cibles, pas là où est votre équipe : c'est la règle qui décide d'une architecture multirégion. Un pipeline hébergé à Paris qui interroge des cibles nord-américaines paie 100 à 300 ms de latence par aller-retour, et une panne de zone arrête tout.
L'API CaptchaAI, elle, reste hors de l'équation : elle répond aux requêtes mondiales et se facture au thread concurrent, où que tournent vos workers.
Faut-il vraiment une deuxième région ?
| Signal | Le multi-région vaut l'effort | Une seule région suffit |
|---|---|---|
| Répartition des cibles | Plusieurs zones géographiques distinctes | Cibles concentrées dans une zone |
| Tolérance à la panne | Un incident régional doit rester invisible | Une courte interruption est acceptable |
| Conformité | Certaines sessions doivent être traitées localement | Aucune contrainte de résidence |
| Volumétrie | Les pics justifient routage et observabilité | Volume faible et stable |
Trois lignes sur quatre à droite : gardez une région unique.
Le schéma cible
[Task Router]
(Route53 / Load Balancer)
↙ ↓ ↘
[US-East] [EU-West] [AP-Southeast]
Workers Workers Workers
↓ ↓ ↓
[CaptchaAI API] ← shared API key
↓ ↓ ↓
[Central DB / Queue]
(Results aggregation)
Chaque région exécute ses propres workers, partage la même clé API CaptchaAI et pousse ses résultats vers un stockage central, le seul endroit d'où vous voyez le débit par région.
Région unique ou distribuée : ce qui change
| Situation | Région unique | Multi-région |
|---|---|---|
| Cibles dans un seul pays | Suffisant | Surdimensionné |
| Cibles mondiales | 100 à 300 ms ajoutées | Latence locale |
| Disponibilité élevée | Difficile sans redondance | Redondance naturelle |
| Résidence des données imposée | Contrainte non tenable | Traitement local |
| Moins de 1 000 tâches/heure | Largement suffisant | Complexité inutile |
| Plus de 10 000 tâches/heure | Plafond de mise à l'échelle | Charge répartie |
Déployer des workers conscients de leur région
Un worker multirégion étiquette chaque résultat avec sa région d'exécution.
Worker Python sensible à la région
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}
Le champ region et la durée voyagent avec chaque résultat : vous obtenez une médiane de temps de résolution par zone sans instrumentation.
Router les tâches vers la bonne file
Le routage se fait sur le domaine de la cible : un site en .fr part vers eu-west-3 (Paris), un site en .jp vers Tokyo.
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
Pour les .com européens, ajoutez une table d'exceptions explicite.
Provisionner l'infrastructure
Squelette 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"
}
Une file d'entrée par région, une file de résultats centrale : l'agrégation reste simple.
Simuler trois régions en local avec Docker Compose
Validez le routage en local avant de payer trois flottes cloud.
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
Surveiller la santé de chaque région
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);
Exposez l'endpoint de santé sur un chemin distinct de la résolution : sinon un worker saturé se déclare sain jusqu'au bout.
Basculer quand une région tombe
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
La cible du basculement est la région saine dont la file est la plus courte, pas la plus proche. Gardez 30 % de marge ailleurs, sinon la panne devient saturation globale.
Ce que coûte réellement le multi-région
| Composant | Facteur de coût | Optimisation |
|---|---|---|
| Instances de worker | Calcul par région | Mise à l'échelle automatique à zéro |
| Transfert inter-régions | 0,02 $/Go | Réduire la taille des payloads |
| Files SQS | Tarification à la requête | Regrouper les messages par lots |
| API CaptchaAI | Coût identique partout | Aucun supplément multirégion |
La facturation CaptchaAI porte sur les threads concurrents, avec des résolutions illimitées par thread. Un plan ADVANCE ($90/mois, 50 threads) offre la même capacité à Paris, en Virginie ou à Singapour : répartir ces threads sur trois régions ne change pas la facture. Le surcoût reste infrastructurel.
Résidence des données : le réflexe RGPD
Dès que vos tâches transportent des données personnelles, la région n'est plus un arbitrage de latence. Traitez les tâches européennes dans une région européenne — eu-west-3 (Paris), eu-central-1 (Francfort), OVHcloud ou Scaleway. N'envoyez à la file centrale que l'identifiant de tâche, le token et l'horodatage, jamais le contenu de la page, et validez vos obligations RGPD avec votre DPO.
Dépannage
| Problème | Cause probable | Correctif |
|---|---|---|
| Une région toujours plus lente | Distance réseau vers les cibles | Comparez d'abord la latence de référence |
| Tout part vers une seule file | Mappage TLD trop grossier | Ajoutez une table d'exceptions par domaine |
| Le basculement ne se déclenche pas | Endpoint de santé répondant à tort | Séparez-le du worker, surveillez la file |
| Le solde descend vite | Régions partageant les mêmes threads | Attendu : suivez la consommation agrégée |
FAQ
Combien de régions faut-il pour commencer ?
Deux, dans deux zones distinctes. Une troisième en Asie ne se justifie que si vos cibles y sont nombreuses.
Comment répartir les threads de mon plan entre les régions ?
Les threads sont un plafond de concurrence global sur votre clé API : c'est au routeur de limiter les tâches en vol par région.
Le multi-région améliore-t-il le taux de réussite ?
Pas directement : il réduit la latence et absorbe les pannes de zone. Les gains viennent de la cohérence entre proxy et session.
Peut-on traiter les tâches européennes uniquement en Europe ?
Oui : routez par TLD vers une file européenne et ne déployez que des workers européens derrière elle.
Articles connexes
Prochaines étapes
Commencez par deux régions et mesurez la latence réelle une semaine. Récupérez votre clé API et déployez votre premier worker régional.
Guides associés :