CAPTCHA çözümü için 7/24 açık bir sunucu tutmak pahalıdır. AWS Lambda ile fonksiyon yalnızca çözüm isteği geldiğinde çalışır; boştayken ödeme yapmazsınız. CaptchaAI'nin HTTP API'siyle birleşince sonuç kendi kendine ölçeklenen bir çözüm hattı olur: istek alın, CaptchaAI'ye gönderin, token'ı döndürün. Bu rehber tek bir Lambda fonksiyonunu handler'dan Secrets Manager ve SQS'e kadar sıfırdan yayına alır.
Mimari: istekten token'a akış
Kurulumun tamamı üç parçadan oluşur ve her biri diğerlerinden bağımsız ölçeklenir:
- API Gateway veya SQS gelen isteği karşılar ve Lambda'yı tetikler.
- Lambda fonksiyonu görevi CaptchaAI'ye gönderir, sonucu sorgular ve token'ı döndürür.
- Secrets Manager API anahtarınızı kodun dışında, şifreli tutar.
Bu ayrım sayesinde trafik arttığında yalnızca Lambda eşzamanlılığı büyür; yönetmeniz gereken bir sunucu ya da ölçek grubu kalmaz. Aşağıdaki bölümlerde bu üç parçayı sırayla kuracağız.
Lambda handler'ı: gönder ve sorgula
Handler görevi CaptchaAI'ye gönderir (in.php) ve sonucu res.php üzerinden sorgular; urllib yerleşik olduğu için ekstra bağımlılık ya da Lambda katmanı gerekmez. Çözme mantığını ayrı bir solve_captcha fonksiyonuna taşımak, aynı kodu hem API Gateway hem de SQS tetikleyicisinde yeniden kullanmanızı sağlar.
# lambda_function.py
import json
import os
import time
import urllib.request
import urllib.parse
def lambda_handler(event, context):
"""AWS Lambda handler for CaptchaAI solving."""
api_key = os.environ["CAPTCHAAI_KEY"]
# Parse input
body = json.loads(event.get("body", "{}")) if isinstance(event.get("body"), str) else event
method = body.get("method", "userrecaptcha")
params = body.get("params", {})
try:
token = solve_captcha(api_key, method, params)
return {
"statusCode": 200,
"body": json.dumps({"token": token}),
}
except Exception as e:
return {
"statusCode": 500,
"body": json.dumps({"error": str(e)}),
}
def solve_captcha(api_key, method, params, timeout=90):
"""Solve CAPTCHA using CaptchaAI API."""
# Submit task
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"]
# Poll for result
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")
Fonksiyon iki aşamalı çalışır: önce görevi gönderip bir task_id alır, ardından res.php uç noktasını beş saniyede bir sorgulayarak CAPCHA_NOT_READY yanıtı bitene kadar bekler. Zaman aşımı süresi dolarsa TimeoutError fırlatır, böylece fonksiyon takılı kalmaz.
API anahtarını Secrets Manager'da saklayın
API anahtarını koda ya da ortam değişkenine gömmek yerine AWS Secrets Manager'da tutun; fonksiyon anahtarı çalışma anında okur ve değer log'lara sızmaz. Bu, KVKK kapsamındaki denetimlerde beklenen sır yönetimi pratiğidir.
import json
import boto3
def get_api_key():
"""Retrieve CaptchaAI key from AWS Secrets Manager."""
client = boto3.client("secretsmanager")
response = client.get_secret_value(SecretId="captchaai/api-key")
secret = json.loads(response["SecretString"])
return secret["api_key"]
Sırrı bir kez oluşturun:
aws secretsmanager create-secret \
--name captchaai/api-key \
--secret-string '{"api_key":"YOUR_API_KEY"}'
Fonksiyona yalnızca bu tek sırrı okuma izni verin; geniş secretsmanager:* izinleri yerine kaynak ARN'sini daraltmak en az ayrıcalık ilkesine uyar.
SAM şablonu: altyapıyı kod olarak tanımlayın
SAM şablonu fonksiyonu, /solve uç noktasını ve Secrets Manager iznini tek dosyada tanımlar. Altyapıyı kod olarak tutmak, aynı yığını farklı bölgelerde ya da staging ortamında tekrarlanabilir biçimde kurmanızı sağlar.
# template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 120
MemorySize: 256
Runtime: python3.11
Resources:
CaptchaSolverFunction:
Type: AWS::Serverless::Function
Properties:
Handler: lambda_function.lambda_handler
Environment:
Variables:
CAPTCHAAI_KEY: !Sub "{{resolve:secretsmanager:captchaai/api-key:SecretString:api_key}}"
Events:
SolveApi:
Type: Api
Properties:
Path: /solve
Method: post
Policies:
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:captchaai/api-key-*"
Outputs:
SolveApiUrl:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/solve"
Fonksiyonu yayına alın
İki komutla derleyip yayına alın; --guided bayrağı ilk dağıtımda bölgeyi ve yığın adını sorar, sonraki dağıtımlarda kaydedilen ayarları kullanır.
# Build and deploy
sam build
sam deploy --guided
# Test
curl -X POST https://YOUR_API_ID.execute-api.us-east-1.amazonaws.com/Prod/solve \
-H "Content-Type: application/json" \
-d '{
"method": "userrecaptcha",
"params": {
"googlekey": "SITE_KEY",
"pageurl": "https://example.com"
}
}'
Dönen SolveApiUrl çıktısını not edin; entegrasyon testlerinizde bu uç noktaya POST isteği göndereceksiniz.
SQS ile toplu CAPTCHA işleme
Yüksek hacimli işlerde istekleri doğrudan API Gateway yerine bir SQS kuyruğuna yazın. Lambda kuyruğu toplu tüketir ve ani yükleri tamponlar; böylece bir trafik sıçraması eşzamanlılık limitine çarpıp istekleri düşürmez. Türk e-ticaret ekiplerinin kampanya dönemlerinde checkout akışlarını test ederken gördüğü hacim dalgalanmaları için bu desen özellikle uygundur.
import json
import os
import time
import urllib.request
import urllib.parse
def sqs_handler(event, context):
"""Process CAPTCHA tasks from SQS queue."""
api_key = os.environ["CAPTCHAAI_KEY"]
results = []
for record in event["Records"]:
task = json.loads(record["body"])
try:
token = solve_captcha(
api_key,
task["method"],
task["params"],
)
results.append({
"task_id": task.get("id"),
"status": "success",
"token": token[:50],
})
except Exception as e:
results.append({
"task_id": task.get("id"),
"status": "error",
"error": str(e),
})
return {"results": results}
Kuyruk ayrıca yeniden deneme ve ölü mektup kuyruğu (dead-letter queue) davranışını üstlenir: çözülemeyen görevler kaybolmaz, incelemek üzere ayrı bir kuyruğa taşınır.
Lambda yapılandırmasında dikkat edilecekler
Fonksiyonu üretime almadan önce aşağıdaki ayarları çözüm sürenize göre gözden geçirin:
| Faktör | Değer |
|---|---|
| Maksimum zaman aşımı | 15 dakika (çoğu CAPTCHA için 2 dakikaya ayarlanmıştır) |
| Bellek | 256 MB yeterli (yoğun işlem yok) |
| Eşzamanlılık | Varsayılan 1000 eşzamanlı (gerekirse artış isteyin) |
| Soğuk başlatma | Python için ~500ms (çözüm süresine karşı ihmal edilebilir) |
| Maliyet | ~Çözüm başına 0,0001$ (yalnızca hesaplama) |
| Bağımlılıklar | Lambda katmanlarından tanılamak için urllib (yerleşik) kullanın |
Sorun giderme
En sık karşılaşılan dört sorun ve hızlı çözümleri:
| Sorun | Sebep | Düzeltme |
|---|---|---|
| İşlev zaman aşımına uğradı | Lambda zaman aşımı < çözüm süresi | Zaman aşımını 120 saniyeden fazla olarak ayarlayın |
| İzin gizli olarak reddedildi | Eksik IAM politikası | SecretsManager okuma politikasını ekleyin |
| Soğuk başlatma gecikmeyi artırır | Seyrek çağrılar | Sağlanan eşzamanlılığı kullan |
| İstekler için içe aktarma hatası | Lambda'da paketlenmemiştir | urllib.request (yerleşik) kullanın veya katman ekleyin |
Maliyet: sunucusuz gerçekten ucuz mu?
Sunucusuz modelin cazibesi boşta maliyetin sıfır olmasıdır. Çözüm başına Lambda hesaplama ücreti yaklaşık 0,0001$ seviyesindedir; asıl gider CaptchaAI thread planınızdır. Sabit bir worker'ı 7/24 açık tutmak yerine yalnızca gelen isteği ödersiniz, bu da değişken ve düşük hacimli iş yüklerinde belirgin bir tasarruf sağlar.
Eşzamanlı çözüm kapasitesi Lambda tarafında değil, plan thread sayınızda belirlenir. Düşük hacim için BASIC ($15/ay, 5 thread), yoğun kampanya yükleri için ADVANCE ($90/ay, 50 thread) veya PREMIUM ($170/ay, 100 thread) uygundur. Fiyatlar USD cinsindendir; TL kuru oynadıkça öngörülebilir aylık USD gideri, sunucusuz kurulumun ek bir avantajıdır.
Sık sorulan sorular
Sunucusuz Lambda mı, sürekli çalışan bir worker mı seçmeliyim?
Değişken veya düşük hacimli iş yüklerinde Lambda daha ekonomiktir; yalnızca çözüm yaparken ödeme yaparsınız. Sabit ve çok yüksek hacimli akışlarda sürekli çalışan bir worker daha öngörülebilir olabilir.
Aynı anda çok sayıda CAPTCHA çözersem hangi plana ihtiyacım olur?
Eşzamanlılık Lambda tarafında değil, CaptchaAI thread sayısında sınırlanır. Düşük hacim için BASIC ($15/ay, 5 thread), yoğun yükler için ADVANCE ($90/ay, 50 thread) veya PREMIUM ($170/ay, 100 thread) uygundur. Fiyatlar USD'dir ve thread başınadır.
Lambda zaman aşımını kaç saniyeye ayarlamalıyım?
Çoğu CAPTCHA 10–60 saniyede çözülür. Zaman aşımını 120 saniyeye ayarlayın; reCAPTCHA Enterprise gibi ağır türlerde 180 saniyeye çıkarın. Zaman aşımı çözüm süresinden kısa kalırsa fonksiyon erken sonlanır.
API anahtarımı ortam değişkeninde tutmak güvenli mi?
Kısa testlerde yeterli olsa da üretimde anahtarı Secrets Manager'da tutun ve erişimi IAM ile sınırlayın; böylece anahtar log'lara sızmaz.
İlgili rehberler
Sunucusuz mimariye geçin — CaptchaAI anahtarınızı alın ve ilk çözümünüzü bugün çalıştırın.