DevOps & Scaling

AWS SNS ve CaptchaAI ile Olay Odaklı CAPTCHA Çözümü Oluşturma

CAPTCHA sonucunu beklerken thread'leri meşgul tutmak, yüksek hacimli otomasyonlarda boşa giden kapasitedir. Daha temiz yol olay odaklı bir akıştır.

Bu yaklaşımda CaptchaAI çözümü bitirince sonucu bir callback ile iletir, siz bunu AWS SNS (Simple Notification Service) konusuna yayınlarsınız ve SQS, Lambda ya da e-posta gibi tüketiciler sonucu birbirinden bağımsız işler.

Bu rehberde sorgulama tabanlı bir akıştan SNS destekli olay odaklı mimariye geçişi beş adımda kuruyoruz.

Neden sorgulama yerine olay odaklı akış?

Sürekli sorgulama (polling), her aktif görev için bir thread'i sonuç gelene kadar bloke eder. Onlarca eşzamanlı CAPTCHA çözerken bu hem kod karmaşıklığı hem de gereksiz istek demektir. İki yaklaşımı yan yana koyalım:

Kriter Sorgulama Olay odaklı
Thread kullanımı Sonuç gelene kadar bloke Görevi gönderip serbest kalır
Ölçeklenme Kapasite hızla dolar Tüketiciler bağımsız ölçeklenir
Kod karmaşıklığı Döngü + zaman aşımı yönetimi Callback + tüketici ayrımı
Gecikme Sorgulama aralığına bağlı Sonuç hazır olunca anında

Örneğin İstanbul merkezli bir e-ticaret ekibi, kampanya günlerinde binlerce ödeme ve giriş akışını QA ortamında doğrularken tek bir callback hattını yüzlerce tüketiciye dağıtabilir.

Kazınan verinin kişisel veri içermesi hâlinde KVKK kapsamına girdiğini unutmayın; bu mimariyi yetkili QA ve veri toplama iş akışlarıyla sınırlı tutun.

Mimari nasıl işliyor

[Scraper] → Submit CAPTCHA → [CaptchaAI API]
                                    ↓
                            Solve completes
                                    ↓
                            Callback → [API Gateway + Lambda]
                                    ↓
                            Publish → [SNS Topic]
                                    ↓
                    ┌───────────────┼───────────────┐
                    ↓               ↓               ↓
            [SQS Queue]      [Lambda Logger]   [Email Alert]
            (result store)   (audit trail)     (on failure)

SNS fan-out (dağıtım) sağlar: tek bir CAPTCHA sonucu, callback işleyicisinin bunlardan haberi bile olmadan birden fazla tüketiciyi tetikler. Akıştaki bileşenlerin rolleri şöyle ayrışır:

  • Callback Lambda: sonucu alır, doğrular ve SNS konusuna yayınlar.
  • SNS konusu: sonucu tüm abonelere aynı anda dağıtır.
  • Tüketiciler: SQS, Lambda ve e-posta sonucu birbirinden bağımsız işler.

Başlamadan önce

Bu hattı kurmadan önce elinizde şunlar olmalı:

  • Aktif bir CaptchaAI hesabı ve API anahtarı.
  • SNS, SQS ve Lambda oluşturma izni olan bir AWS hesabı.
  • Callback'i yayınlayacak, dışarıya açık bir API Gateway uç noktası.

Adım 1: SNS konusunu oluşturun

Önce sonuçların yayınlanacağı SNS konusunu oluşturun. AWS CLI ile boto3, ikisi de aynı konu ARN'sini üretir.

AWS CLI

aws sns create-topic --name captcha-results --output text
# Returns: arn:aws:sns:us-east-1:123456789:captcha-results

Python (boto3)

import boto3

sns = boto3.client("sns", region_name="us-east-1")

response = sns.create_topic(Name="captcha-results")
topic_arn = response["TopicArn"]
print(f"Topic ARN: {topic_arn}")

Adım 2: Callback alıcısını kurun

Bu Lambda işlevi, CaptchaAI callback sonucunu API Gateway üzerinden alır, doğrular ve SNS konusuna yayınlar.

Callback'i olabildiğince ince tutun; tüm iş mantığını tüketici tarafına bırakırsanız işleyici hızlı kalır ve zaman aşımı riskini düşürürsünüz.

Python (Lambda handler)

import json
import os
import boto3

sns = boto3.client("sns")
TOPIC_ARN = os.environ["SNS_TOPIC_ARN"]


def lambda_handler(event, context):
    """Receive CaptchaAI callback and publish to SNS."""
    # Parse query parameters from API Gateway
    params = event.get("queryStringParameters", {}) or {}
    task_id = params.get("id", "")
    solution = params.get("code", "")

    if not task_id or not solution:
        return {"statusCode": 400, "body": "Missing id or code"}

    # Publish to SNS
    message = {
        "task_id": task_id,
        "solution": solution,
        "status": "solved"
    }

    sns.publish(
        TopicArn=TOPIC_ARN,
        Message=json.dumps(message),
        Subject="captcha-solved",
        MessageAttributes={
            "task_id": {
                "DataType": "String",
                "StringValue": task_id
            }
        }
    )

    return {"statusCode": 200, "body": "OK"}

JavaScript (Lambda handler)

const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns");

const sns = new SNSClient({ region: "us-east-1" });
const TOPIC_ARN = process.env.SNS_TOPIC_ARN;

exports.handler = async (event) => {
  const params = event.queryStringParameters || {};
  const taskId = params.id;
  const solution = params.code;

  if (!taskId || !solution) {
    return { statusCode: 400, body: "Missing id or code" };
  }

  const message = {
    task_id: taskId,
    solution: solution,
    status: "solved",
  };

  await sns.send(
    new PublishCommand({
      TopicArn: TOPIC_ARN,
      Message: JSON.stringify(message),
      Subject: "captcha-solved",
      MessageAttributes: {
        task_id: { DataType: "String", StringValue: taskId },
      },
    })
  );

  return { statusCode: 200, body: "OK" };
};

Adım 3: CAPTCHA'ları callback URL'siyle gönderin

CaptchaAI'nin pingback parametresini API Gateway uç noktanıza yönlendirin; çözüm tamamlandığında sonuç doğrudan bu adrese iletilir:

Python

import os
import requests

API_KEY = os.environ["CAPTCHAAI_API_KEY"]
CALLBACK_URL = os.environ["CALLBACK_GATEWAY_URL"]  # API Gateway URL


def submit_captcha(sitekey, pageurl):
    """Submit CAPTCHA with SNS-backed callback."""
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "pingback": CALLBACK_URL,
        "json": 1
    })
    data = resp.json()

    if data.get("status") == 1:
        return data["request"]  # task_id
    raise RuntimeError(f"Submit failed: {data.get('request')}")

Adım 4: Tüketicileri abone edin

Aynı konuya farklı protokollerle birden fazla tüketici abone edin: sonuç deposu için SQS, denetim izi için Lambda, hata bildirimi için e-posta.

SQS kuyruğu (sonuç deposu)

# Subscribe an SQS queue to receive all results
sqs_arn = "arn:aws:sqs:us-east-1:123456789:captcha-results-queue"

sns.subscribe(
    TopicArn=topic_arn,
    Protocol="sqs",
    Endpoint=sqs_arn
)

Lambda (denetim kaydedici)

# Subscribe a Lambda for audit logging
lambda_arn = "arn:aws:lambda:us-east-1:123456789:function:captcha-audit-logger"

sns.subscribe(
    TopicArn=topic_arn,
    Protocol="lambda",
    Endpoint=lambda_arn
)

E-posta (hata uyarıları)

# Subscribe email for error notifications with filter
sns.subscribe(
    TopicArn=topic_arn,
    Protocol="email",
    Endpoint="ops@example.com"
)

Adım 5: Sonuçları SQS'ten okuyun

Kazıyıcınız artık CaptchaAI'yi sorgulamak yerine çözümleri SQS'ten okur. Uzun sorgulama (long polling) sayesinde kuyruk boşken bile istekleri verimli tutarsınız:

Python

import json
import boto3

sqs = boto3.client("sqs", region_name="us-east-1")
QUEUE_URL = os.environ["SQS_QUEUE_URL"]


def get_solved_captcha(timeout=30):
    """Wait for a CAPTCHA solution from the SQS queue."""
    response = sqs.receive_message(
        QueueUrl=QUEUE_URL,
        MaxNumberOfMessages=1,
        WaitTimeSeconds=min(timeout, 20)  # Long polling (max 20s)
    )

    messages = response.get("Messages", [])
    if not messages:
        return None

    msg = messages[0]
    # SNS wraps the message — unwrap it
    sns_envelope = json.loads(msg["Body"])
    result = json.loads(sns_envelope["Message"])

    # Delete message after processing
    sqs.delete_message(
        QueueUrl=QUEUE_URL,
        ReceiptHandle=msg["ReceiptHandle"]
    )

    return result

JavaScript

const {
  SQSClient,
  ReceiveMessageCommand,
  DeleteMessageCommand,
} = require("@aws-sdk/client-sqs");

const sqs = new SQSClient({ region: "us-east-1" });
const QUEUE_URL = process.env.SQS_QUEUE_URL;

async function getSolvedCaptcha(timeout = 30) {
  const response = await sqs.send(
    new ReceiveMessageCommand({
      QueueUrl: QUEUE_URL,
      MaxNumberOfMessages: 1,
      WaitTimeSeconds: Math.min(timeout, 20),
    })
  );

  const messages = response.Messages || [];
  if (messages.length === 0) return null;

  const msg = messages[0];
  const snsEnvelope = JSON.parse(msg.Body);
  const result = JSON.parse(snsEnvelope.Message);

  await sqs.send(
    new DeleteMessageCommand({
      QueueUrl: QUEUE_URL,
      ReceiptHandle: msg.ReceiptHandle,
    })
  );

  return result;
}

SNS mesaj filtreleme

Her tüketicinin her mesajı işlemesi gerekmez. FilterPolicy ile bir abone yalnızca ilgilendiği sonuçları alır — örneğin başarısız çözümleri ayrı bir operasyon kuyruğuna yönlendirin:

# Only send failures to the ops queue
sns.subscribe(
    TopicArn=topic_arn,
    Protocol="sqs",
    Endpoint=failure_queue_arn,
    Attributes={
        "FilterPolicy": json.dumps({
            "status": ["failed", "error"]
        })
    }
)

Maliyet ve ölçeklendirme: thread tabanlı faturalandırma

CaptchaAI çözüm başına değil, eşzamanlı thread başına faturalandırır ve her plan o ay için thread başına sınırsız çözüm içerir. Olay odaklı mimari tam da burada tasarruf sağlar: thread görevi gönderip hemen serbest kaldığı için aynı bütçeyle çok daha fazla eşzamanlı CAPTCHA taşırsınız. Hacme göre başlangıç noktaları:

  • BASIC ($15/ay, 5 thread): küçük ekipler ve ilk entegrasyon.
  • STANDARD ($30/ay, 15 thread): orta hacimli QA ve veri toplama.
  • ADVANCE ($90/ay, 50 thread): kampanya günlerinde yoğun eşzamanlılık.

SNS ve SQS ücretleri tamamen AWS tarafındadır ve mesaj hacmiyle ölçeklenir; CaptchaAI faturanızdan bağımsızdır.

Türkiye'deki geliştiriciler için USD bazlı aylık planların bir avantajı da öngörülebilirliktir — TL kurundaki oynaklık göz önüne alındığında sabit bir thread bütçesi, kapasite planlamasını okunaklı kılar.

İdempotensi ve teslim modeli

SNS mesajları en az bir kez teslim eder; aynı sonuç nadiren de olsa iki kez işlenebilir. Üretimde hattı kararlı tutmak için:

  • İşlemeden önce task_id'yi kalıcı bir depoda (DynamoDB, Redis) kontrol edin; daha önce görülmüşse atlayın.
  • Sıralı işleme ihtiyacınız varsa SNS FIFO konusunu SQS FIFO kuyruğuyla eşleştirin ve MessageGroupId'yi görev kimliğine ayarlayın.
  • Tüketici hata verdiğinde mesajı hemen silmeyin; SQS görünürlük zaman aşımından sonra yeniden denenmesine izin verin.

Böyle bir düzen, yeniden teslimlerin veri bütünlüğünü bozmadığı, üretimde kararlı bir hat verir.

Sorun giderme

Sorun Sebep Düzeltme
Callback 403 döndürüyor API Gateway kimlik doğrulaması CaptchaAI'yi engelliyor Callback yolunda kimlik doğrulamayı kapatın; yerine token tabanlı doğrulama kullanın
SQS mesajları gelmiyor SNS'ten SQS'e yayın izni eksik SQS kuyruk politikasına sns:Publish iznini ekleyin
Aynı sonuç iki kez işleniyor SNS en az bir kez teslim eder İdempotensi uygulayın — işlemeden önce task_id'yi kontrol edin
Lambda soğuk başlangıcı callback'i geciktiriyor Provisioned concurrency ayarlı değil Callback Lambda için provisioned concurrency'yi etkinleştirin

Sık sorulan sorular

Sorgulama yerine neden olay odaklı akış tercih edeyim?

Sorgulama, her aktif görev için bir thread'i sonuç gelene kadar bloke eder. Olay odaklı akışta ise thread görevi gönderip serbest kalır; sonuç hazır olduğunda callback tetiklenir.

Böylece daha yüksek eşzamanlılığı daha az kaynakla taşır, thread bütçenizi verimli kullanırsınız.

Bu mimari CaptchaAI faturamı nasıl etkiler?

CaptchaAI thread tabanlı faturalandırır, çözüm başına değil; SNS ve SQS maliyetleri AWS tarafındadır. BASIC ($15/ay, 5 thread) ile başlayıp eşzamanlı thread ihtiyacınıza göre üst planlara geçebilirsiniz.

Callback uç noktamı nasıl güvence altına alırım?

API Gateway kimlik doğrulamasını callback yolunda kapatıp bunun yerine paylaşılan bir gizli anahtarla token tabanlı doğrulama yapın.

Ayrıca gelen id ve code alanlarını doğrulayın ve task_id ile idempotensi sağlayarak yinelenen teslimleri güvenle eleyin.

SNS katmanı ne kadar ek gecikme getirir?

SNS mesaj başına yaklaşık 10–50 ms ekler. CAPTCHA çözümleri 5–30 saniye sürdüğü için bu ek yük pratikte ihmal edilebilir düzeydedir.

Hangi CAPTCHA türleri bu mimariyle çalışır?

Callback hattı çözüm türünden bağımsızdır: reCAPTCHA v2 ve v3, Cloudflare Turnstile, GeeTest v3 ve görüntü/OCR CAPTCHA'ları aynı pingback akışını kullanır. Örnek kod userrecaptcha yöntemini gösterir; başka bir tür için yalnızca gönderim parametrelerini değiştirir, SNS ve SQS katmanına hiç dokunmazsınız.

Üretime almadan önce kontrol listesi

Hattı canlıya almadan önce şunları doğrulayın:

  • Callback yolunda token tabanlı doğrulama etkin.
  • Her tüketici idempotent ve task_id denetimli.
  • SQS için bir ölü mektup kuyruğu (DLQ) tanımlı.
  • CloudWatch alarmları SNS teslim hatalarını izliyor.

Ne zaman sorgulama yeterli kalır?

Her senaryo olay odaklı mimari gerektirmez. Şu durumlarda düz sorgulama daha basit kalır:

  • Düşük hacimli, ara sıra yapılan tekil çözümlerde.
  • Callback alacak, dışarıya açık bir uç noktanız yoksa.
  • Prototip ve yerel geliştirme testlerinde.

İlgili makaleler

Sonraki adımlar

Olay odaklı CAPTCHA çözümünü bugün kurun — CaptchaAI API anahtarınızı alın ve AWS olay hattınıza bağlayın.

İlgili kılavuzlar:

Bu makale için yorumlar devre dışı bırakılmıştır.