DevOps & Scaling

Azure İşlevleri + CaptchaAI: Bulut Entegrasyonu

Bir POST isteği alıp token döndüren tek bir Azure İşlevi, CaptchaAI'yi bulut iş akışınıza eklemenin en pratik yoludur. Bu rehber, CaptchaAI API'sini Azure İşlevleri üzerinde uçtan uca kuruyor: HTTP tetikleyicili tek bir çözüm işlevinden, API anahtarını Key Vault'ta güvende tutmaya ve Queue Storage ile toplu işlemeye kadar.

Çözüm istekleri düzensiz ve kısa sürelidir; olay güdümlü (event-driven) bir işlev bu profile doğal biçimde oturur. Azure tarafında gereken parçalar da hazırdır — sırlar için Key Vault, görev dağıtımı için Queue Storage ve gözlemlenebilirlik için Application Insights — böylece altyapı kurmakla değil çözüm mantığıyla ilgilenirsiniz.

Örneklerin tamamı Python; aynı akış Node.js, PHP, Go ve diğer diller için de aynı in.php / res.php uç noktalarıyla çalışır.


Ön koşullar

Kuruluma geçmeden önce ortamınızda şunların hazır olması gerekir:

  • Etkin bir Azure aboneliği ve kurulu Azure CLI (az)
  • Azure Functions Core Tools v4 (func komutu)
  • Python 3.11 çalışma zamanı
  • Panelinizden aldığınız bir CaptchaAI API anahtarı

Bu dört parçayı hazırladıysanız uçtan uca kurulum yaklaşık on beş dakika sürer.


HTTP tetikleyicili çözüm işlevi

Temel yapı taşı, bir POST isteği alan ve token döndüren tek bir işlevdir. Aşağıdaki solve yardımcı fonksiyonu görevi in.php'ye gönderir, ardından res.php'yi beş saniyede bir sorgular (periyodik sorgulama) ve sonuç hazır olduğunda token'ı döndürür. timeout parametresi, çözüm bu süre içinde tamamlanmazsa isteği güvenli biçimde sonlandırır — böylece işlev sonsuza kadar açık kalmaz.

# function_app.py
import json
import time
import os
import logging
import urllib.request
import urllib.parse
import azure.functions as func

app = func.FunctionApp()


@app.route(route="solve", methods=["POST"])
def solve_captcha(req: func.HttpRequest) -> func.HttpResponse:
    """HTTP trigger for CAPTCHA solving."""
    try:
        body = req.get_json()
    except ValueError:
        return func.HttpResponse(
            json.dumps({"error": "JSON body required"}),
            status_code=400,
            mimetype="application/json",
        )

    method = body.get("method", "userrecaptcha")
    params = body.get("params", {})
    api_key = os.environ["CAPTCHAAI_KEY"]

    try:
        token = solve(api_key, method, params)
        return func.HttpResponse(
            json.dumps({"token": token}),
            mimetype="application/json",
        )
    except Exception as e:
        logging.error(f"Solve failed: {e}")
        return func.HttpResponse(
            json.dumps({"error": str(e)}),
            status_code=500,
            mimetype="application/json",
        )


def solve(api_key, method, params, timeout=90):
    """Solve CAPTCHA via CaptchaAI API."""
    submit_data = urllib.parse.urlencode({
        "key": api_key,
        "method": method,
        "json": 1,
        **params,
    }).encode()

    req = urllib.request.Request(
        "https://ocr.captchaai.com/in.php",
        data=submit_data,
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        result = json.loads(resp.read())

    if result.get("status") != 1:
        raise RuntimeError(f"Submit error: {result.get('request')}")

    task_id = result["request"]

    start = time.time()
    while time.time() - start < timeout:
        time.sleep(5)
        poll_url = (
            f"https://ocr.captchaai.com/res.php"
            f"?key={api_key}&action=get&id={task_id}&json=1"
        )
        with urllib.request.urlopen(poll_url, timeout=15) as resp:
            data = json.loads(resp.read())

        if data["request"] != "CAPCHA_NOT_READY":
            if data.get("status") == 1:
                return data["request"]
            raise RuntimeError(f"Solve error: {data['request']}")

    raise TimeoutError("Solve timeout")

Varsayılan method değeri userrecaptcha olduğu için işlev, gövdede method göndermezseniz reCAPTCHA v2 çözer. Turnstile için turnstile, GeeTest v3 için geetest gönderin — CaptchaAI'nin desteklediği türlerin her biri aynı işlevi yeniden kullanır.


API anahtarını Key Vault'ta saklama

API anahtarını asla uygulama koduna veya depoya gömmeyin. Azure Key Vault'ta saklayın ve işleve yönetilen kimlik (managed identity) üzerinden erişim verin:

# Create Key Vault
az keyvault create \
  --name captchaai-vault \
  --resource-group myResourceGroup

# Store secret
az keyvault secret set \
  --vault-name captchaai-vault \
  --name CaptchaAIKey \
  --value "YOUR_API_KEY"

# Grant function access
az webapp identity assign \
  --name my-captcha-function \
  --resource-group myResourceGroup

az keyvault set-policy \
  --name captchaai-vault \
  --object-id <principal-id> \
  --secret-permissions get

Uygulama ayarında Key Vault referansı

Ardından uygulama ayarlarında anahtarı doğrudan değil, bir Key Vault referansı olarak tanımlayın. İşlev çalışma zamanında değeri çözer; anahtar hiçbir zaman düz metin olarak ortam değişkeninde görünmez:

CAPTCHAAI_KEY=@Microsoft.KeyVault(SecretUri=https://captchaai-vault.vault.azure.net/secrets/CaptchaAIKey/)

Queue Storage ile toplu CAPTCHA işleme

Yüzlerce görevi tek tek HTTP çağrısıyla göndermek yerine, bunları Azure Queue Storage'a bırakıp bir kuyruk tetikleyicisiyle işleyin. Bu model yükü tamponlar: ani istek dalgalanmalarında görevler kuyrukta birikir ve işlev, kapasitesine göre birer birer tüketir.

@app.queue_trigger(
    arg_name="msg",
    queue_name="captcha-tasks",
    connection="AzureWebJobsStorage",
)
def process_queue_task(msg: func.QueueMessage):
    """Process CAPTCHA task from queue."""
    task = json.loads(msg.get_body().decode())
    api_key = os.environ["CAPTCHAAI_KEY"]

    try:
        token = solve(api_key, task["method"], task["params"])
        logging.info(f"Task {task['id']} solved")

        # Store result in Table Storage or return queue
        _store_result(task["id"], "success", token)

    except Exception as e:
        logging.error(f"Task {task['id']} failed: {e}")
        _store_result(task["id"], "error", str(e))


def _store_result(task_id, status, value):
    """Store result (simplified — use Table Storage in production)."""
    logging.info(f"Result: {task_id} = {status}")

Burada eşzamanlılık sınırını CaptchaAI planınızın thread sayısı belirler; CaptchaAI thread bazlı faturalandırır ve her thread için sınırsız çözüm sunar:

  • BASIC ($15/ay, 5 thread) — aynı anda beş çözümü karşılar; düşük hacimli kuyruklar için yeterli.
  • ADVANCE ($90/ay, 50 thread) — elli görevi paralel yürütür; sürekli toplu işleme yapan ekipler için uygun.

Kuyruk derinliğini plan thread sayınıza göre ayarlarsanız ne kapasiteyi boşa harcarsınız ne de gereksiz hata alırsınız.


Proje yapısı ve yapılandırma

Minimal bir Azure İşlevleri projesi dört dosyadan oluşur:

captcha-function/
├── function_app.py
├── requirements.txt
├── host.json
└── local.settings.json

requirements.txt:

azure-functions

host.json, işlev başına zaman aşımını belirler. CAPTCHA çözümü periyodik sorgulama nedeniyle uzayabildiği için varsayılanı bilinçli olarak iki dakikaya çekin:

{
  "version": "2.0",
  "functionTimeout": "00:02:00",
  "logging": {
    "logLevel": {
      "default": "Information"
    }
  }
}

local.settings.json, yerel geliştirmede kullanılır ve depoya eklenmez. Üretimde CAPTCHAAI_KEY değeri Key Vault'tan gelir; yerelde ise ayrı bir test anahtarı kullanın:

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "CAPTCHAAI_KEY": "YOUR_API_KEY_FOR_LOCAL_DEV"
  }
}

İşlevi Azure'a dağıtma

İşlev uygulamasını Consumption planında oluşturun ve tek komutla yayına alın. Aşağıdaki curl çağrısı, dağıtımdan sonra uç noktayı hızlıca doğrular:

# Create function app
az functionapp create \
  --resource-group myResourceGroup \
  --consumption-plan-location westus2 \
  --runtime python \
  --runtime-version 3.11 \
  --functions-version 4 \
  --name my-captcha-solver \
  --storage-account mystorageaccount

# Deploy
func azure functionapp publish my-captcha-solver

# Test
curl -X POST https://my-captcha-solver.azurewebsites.net/api/solve \
  -H "Content-Type: application/json" \
  -d '{
    "method": "userrecaptcha",
    "params": {
      "googlekey": "SITE_KEY",
      "pageurl": "https://example.com"
    }
  }'

Yerel senaryo: gece boyunca ödeme adımı testi

İstanbul merkezli bir e-ticaret ekibi, ödeme adımını gece boyunca otomatik test ederken karşılaştığı reCAPTCHA v2'yi bu işlevle çözebilir. Testler Europe/Istanbul saat diliminde zamanlanır, her çalıştırma yalnızca birkaç saniye işlev süresi tüketir ve ekip sabit, öngörülebilir bir USD aylık maliyetle ilerler — TL kurundaki dalgalanmadan bağımsız olarak. (Yalnızca sahibi olduğunuz veya test yetkiniz bulunan ortamlarda kullanın.)


Görevleri kuyruğa gönderme

Toplu iş yüklerinde görevleri kuyruğa yığın halinde bırakın. Aşağıdaki istemci on örnek görevi captcha-tasks kuyruğuna gönderir; kuyruk tetikleyicisi bunları arka planda tüketir:

from azure.storage.queue import QueueClient
import json

queue = QueueClient.from_connection_string(
    conn_str="YOUR_STORAGE_CONNECTION_STRING",
    queue_name="captcha-tasks",
)

# Submit batch
for i in range(10):
    task = {
        "id": f"task-{i}",
        "method": "userrecaptcha",
        "params": {
            "googlekey": "SITE_KEY",
            "pageurl": f"https://example.com/page{i}",
        },
    }
    queue.send_message(json.dumps(task))
    print(f"Queued task-{i}")

Application Insights'ı bağlarsanız her logging.info / logging.error satırı merkezî olarak toplanır; başarı oranını, çözüm süresini ve hata kodlarını tek panelden izleyebilirsiniz.


Sorun giderme

Sorun Sebep Çözüm
İşlev 5 dakikada zaman aşımına uğruyor Varsayılan zaman aşımı çok kısa host.json içinde functionTimeout değerini yükseltin
Key Vault referansı boş dönüyor Yönetilen kimlik veya erişim ilkesi eksik Yönetilen kimliği atayın ve Key Vault ilkesini tanımlayın
Kuyruk iletileri sonsuza kadar yeniden deneniyor İşlev istisna fırlatıyor Bilinen hataları yakalayın, günlüğe yazın ve sonucu döndürün
Soğuk başlatma 10 saniyeyi aşıyor Python çalışma zamanı ilk kez başlıyor Premium plana geçin veya FUNCTIONS_WORKER_PROCESS_COUNT değerini ayarlayın

Sık sorulan sorular

Azure Functions'ta CaptchaAI için hangi plan yeterli?

Eşzamanlı çözüm sayınıza bakın. CaptchaAI thread bazlı faturalandırır: BASIC ($15/ay, 5 thread) düşük hacimli işler için yeterlidir, sürekli toplu işleme yapıyorsanız ADVANCE ($90/ay, 50 thread) daha rahat nefes aldırır. Kuyruk eşzamanlılığını thread sayınızla eşleştirin.

Consumption mu yoksa Premium plan mı seçmeliyim?

Günde 100'ün altındaki düşük hacimlerde Consumption yeterlidir. Tutarlı ve sürekli iş yüklerinde Premium'u tercih edin: bulut sunucularını sıcak tutar, soğuk başlatmaları ortadan kaldırır ve VNET entegrasyonunu destekler.

CaptchaAI hangi CAPTCHA türlerini çözüyor, hepsi Azure'da çalışır mı?

Aynı işlev; yalnızca method parametresi değişir. reCAPTCHA v2/v3, Cloudflare Turnstile ve Challenge, GeeTest v3, görüntü/OCR, grid ve BLS türleri desteklenir; CaptchaFox (beta), Friendly Captcha (beta) ve Lemin (beta) beta aşamasındadır. hCaptcha, FunCaptcha ve GeeTest v4 desteklenmez.

Soğuk başlatma çözüm süresini etkiler mi?

İşlev uzun süre boşta kaldıysa ilk çağrıda birkaç saniyelik ek gecikme olabilir. Gecikmeye duyarlı iş yüklerinde Premium planla sunucuları sıcak tutun veya işlevi periyodik bir "ısıtma" isteğiyle uyanık bırakın.

Karmaşık iş akışları için Durable Functions kullanabilir miyim?

Evet. Durable Functions, fan-out/fan-in desenlerini destekler: onlarca CAPTCHA görevini paralel gönderip tüm sonuçları tek noktada toplayabilirsiniz. Toplu işleme ve çok adımlı akışlar için idealdir.


İlgili Kılavuzlar


Azure'a dağıtın — CaptchaAI anahtarınızı bugün alın.

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