Bir CAPTCHA çözüm hattını üretimde ayakta tutmak için aslında yalnızca üç sinyali izlemeniz yeterlidir: bakiyenin tükenmesi, hata oranının yükselmesi ve worker'ların durması. Bunlardan biri eşiği aştığı anda sorunu fark etmek için panelin başında beklemenize gerek yoktur — bildirim doğrudan nöbetçi mühendise gider.
Bu rehberde tam olarak bunu kuruyoruz: CaptchaAI'nin getbalance uç noktasını ve kendi çözüm metriklerinizi periyodik olarak sorgulayan, eşik aşıldığında PagerDuty Events API v2 üzerinden olay açan küçük bir izleme servisi. Böylece bir aksaklığın kaybettirdiği saatler dakikalara iner ve nöbetçi, günlükleri tek tek açmadan sorunu teşhis edecek bağlamı baştan alır.
Hangi sinyalde kimi uyaralım: CaptchaAI uyarı stratejisi
Her olay aynı aciliyette değildir. İyi bir uyarı stratejisi, gerçekten birini uyandırması gereken durumları (bakiye bitmiş, tüm worker'lar durmuş) düşük öncelikli bilgilendirmelerden (gecikme biraz yükselmiş) ayırır. Aşağıdaki eşikler pratikte iyi çalışan bir başlangıç noktasıdır; kendi hacminize göre ayarlayın.
| Önem | Durum | PagerDuty eylemi |
|---|---|---|
| Kritik | Bakiye < $2 | Nöbetçi mühendisi çağır |
| Kritik | Tüm worker'lar durdu | Nöbetçi mühendisi çağır |
| Yüksek | Hata oranı 5 dakika boyunca > %20 | Acil (urgent) olay oluştur |
| Uyarı | Bakiye < $10 | Düşük öncelikli olay oluştur |
| Uyarı | Kuyruk derinliği 10 dakika boyunca > 100 | Düşük öncelikli olay oluştur |
| Bilgi | Çözüm gecikmesi p95 > 120s | Mevcut olaya ekle veya günlüğe yaz |
İki eşik türünü ayırt etmek önemli. Bakiye eşikleri kesin sayılardır: $2'nin altı, hattın birkaç dakika içinde tamamen durabileceği anlamına gelir; bu bir "hemen uyandır" durumudur. Hata oranı ise pencereli bir metriktir — tek bir başarısız çözüm önemli değildir, ama beş dakikalık pencerede isteklerin beşte birinden fazlası düşüyorsa hedef sitede bir değişiklik ya da altyapınızda bir sorun var demektir. Gecikme ve kuyruk derinliği çoğunlukla "bilgi" seviyesinde kalır: nöbetçiyi uyandırmaz, ama sabah bakıldığında bir eğilimi gösterir.
Python ile izleme servisi: PagerDuty Events API v2
Aşağıdaki servis iki parçadan oluşur. CaptchaPagerDuty sınıfı PagerDuty tarafını yönetir — olay açar (trigger), susturur (acknowledge) ve kapatır (resolve). CaptchaMonitor ise ölçümü yapar: her çözümün sonucunu kayan bir pencerede tutar, hata oranını hesaplar ve getbalance ile bakiyeyi çeker. dedup_key alanına dikkat edin; PagerDuty aynı tekilleştirme anahtarına sahip tekrar eden tetikleyicileri tek bir olayda birleştirir, böylece uyarı seli oluşmaz.
import os
import time
import hashlib
import requests
from datetime import datetime
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
PAGERDUTY_ROUTING_KEY = os.environ["PAGERDUTY_ROUTING_KEY"]
session = requests.Session()
class CaptchaPagerDuty:
EVENTS_URL = "https://events.pagerduty.com/v2/enqueue"
def __init__(self, routing_key):
self.routing_key = routing_key
def trigger(self, summary, severity="error", source="captcha-pipeline",
details=None, dedup_key=None):
"""Trigger a new PagerDuty incident."""
payload = {
"routing_key": self.routing_key,
"event_action": "trigger",
"payload": {
"summary": summary,
"severity": severity, # critical, error, warning, info
"source": source,
"timestamp": datetime.utcnow().isoformat() + "Z",
"custom_details": details or {}
}
}
if dedup_key:
payload["dedup_key"] = dedup_key
resp = requests.post(self.EVENTS_URL, json=payload, timeout=10)
resp.raise_for_status()
return resp.json()
def resolve(self, dedup_key):
"""Resolve an existing incident."""
payload = {
"routing_key": self.routing_key,
"event_action": "resolve",
"dedup_key": dedup_key
}
resp = requests.post(self.EVENTS_URL, json=payload, timeout=10)
resp.raise_for_status()
return resp.json()
def acknowledge(self, dedup_key):
"""Acknowledge an existing incident."""
payload = {
"routing_key": self.routing_key,
"event_action": "acknowledge",
"dedup_key": dedup_key
}
resp = requests.post(self.EVENTS_URL, json=payload, timeout=10)
resp.raise_for_status()
return resp.json()
pagerduty = CaptchaPagerDuty(PAGERDUTY_ROUTING_KEY)
class CaptchaMonitor:
def __init__(self):
self.error_window = [] # (timestamp, is_error)
self.window_size = 300 # 5 minutes in seconds
def record_solve(self, success):
now = time.time()
self.error_window.append((now, not success))
# Prune old entries
self.error_window = [
(t, e) for t, e in self.error_window
if now - t < self.window_size
]
@property
def error_rate(self):
if not self.error_window:
return 0.0
errors = sum(1 for _, e in self.error_window if e)
return errors / len(self.error_window)
def check_balance(self):
resp = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "getbalance", "json": 1
})
data = resp.json()
if data.get("status") != 1:
return None
return float(data["request"])
def run_checks(self):
"""Run all monitoring checks and trigger alerts."""
# Check balance
balance = self.check_balance()
if balance is not None:
if balance < 2:
pagerduty.trigger(
summary=f"CaptchaAI balance critically low: ${balance:.2f}",
severity="critical",
dedup_key="captcha-balance-critical",
details={"balance": balance, "threshold": 2}
)
elif balance < 10:
pagerduty.trigger(
summary=f"CaptchaAI balance low: ${balance:.2f}",
severity="warning",
dedup_key="captcha-balance-warning",
details={"balance": balance, "threshold": 10}
)
else:
# Resolve if balance recovered
try:
pagerduty.resolve("captcha-balance-critical")
pagerduty.resolve("captcha-balance-warning")
except Exception:
pass # No incident to resolve
# Check error rate
rate = self.error_rate
if rate > 0.20:
total = len(self.error_window)
errors = sum(1 for _, e in self.error_window if e)
pagerduty.trigger(
summary=f"CaptchaAI error rate {rate:.0%} "
f"({errors}/{total} in 5 min)",
severity="error",
dedup_key="captcha-error-rate-high",
details={
"error_rate": round(rate, 3),
"total_tasks": total,
"failed_tasks": errors,
"window_seconds": self.window_size
}
)
elif rate < 0.05 and len(self.error_window) > 10:
try:
pagerduty.resolve("captcha-error-rate-high")
except Exception:
pass
monitor = CaptchaMonitor()
# After each solve:
# monitor.record_solve(success=True)
# Run checks every 60 seconds:
# while True:
# monitor.run_checks()
# time.sleep(60)
Çalıştırmak için run_checks fonksiyonunu 60 saniyede bir çağırmanız yeterli; her başarılı ya da başarısız çözümden sonra record_solve ile pencereyi güncellersiniz. Bakiye toparlandığında kod ilgili olayı otomatik olarak resolve eder, yani nöbetçinin olayı elle kapatmasına gerek kalmaz.
Node.js ile aynı entegrasyonu kurma
Yığınınız Node.js üzerindeyse mantık birebir aynıdır: PagerDutyAlerter olayları açıp kapatır, CaptchaHealthMonitor kayan pencerede hata oranını izler. Bakiye axios ile getbalance üzerinden çekilir ve setInterval kontrolü her 60 saniyede bir tetikler.
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const PD_ROUTING_KEY = process.env.PAGERDUTY_ROUTING_KEY;
const PD_EVENTS_URL = "https://events.pagerduty.com/v2/enqueue";
class PagerDutyAlerter {
constructor(routingKey) {
this.routingKey = routingKey;
}
async trigger(summary, severity = "error", details = {}, dedupKey = null) {
const payload = {
routing_key: this.routingKey,
event_action: "trigger",
payload: {
summary,
severity,
source: "captcha-pipeline",
timestamp: new Date().toISOString(),
custom_details: details,
},
};
if (dedupKey) payload.dedup_key = dedupKey;
const resp = await axios.post(PD_EVENTS_URL, payload, { timeout: 10000 });
return resp.data;
}
async resolve(dedupKey) {
await axios.post(PD_EVENTS_URL, {
routing_key: this.routingKey,
event_action: "resolve",
dedup_key: dedupKey,
}, { timeout: 10000 });
}
}
const alerter = new PagerDutyAlerter(PD_ROUTING_KEY);
class CaptchaHealthMonitor {
constructor(windowMs = 300000) {
this.results = [];
this.windowMs = windowMs;
}
record(success) {
this.results.push({ time: Date.now(), success });
const cutoff = Date.now() - this.windowMs;
this.results = this.results.filter((r) => r.time > cutoff);
}
get errorRate() {
if (this.results.length === 0) return 0;
const errors = this.results.filter((r) => !r.success).length;
return errors / this.results.length;
}
async checkAndAlert() {
// Balance check
try {
const resp = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "getbalance", json: 1 },
});
if (resp.data.status === 1) {
const balance = parseFloat(resp.data.request);
if (balance < 2) {
await alerter.trigger(
`CaptchaAI balance critically low: $${balance.toFixed(2)}`,
"critical",
{ balance },
"captcha-balance-critical"
);
} else if (balance < 10) {
await alerter.trigger(
`CaptchaAI balance low: $${balance.toFixed(2)}`,
"warning",
{ balance },
"captcha-balance-warning"
);
} else {
await alerter.resolve("captcha-balance-critical").catch(() => {});
await alerter.resolve("captcha-balance-warning").catch(() => {});
}
}
} catch (err) {
console.error("Balance check failed:", err.message);
}
// Error rate check
const rate = this.errorRate;
if (rate > 0.2 && this.results.length > 10) {
await alerter.trigger(
`CaptchaAI error rate: ${(rate * 100).toFixed(1)}%`,
"error",
{ errorRate: rate, totalTasks: this.results.length },
"captcha-error-rate"
);
} else if (rate < 0.05 && this.results.length > 10) {
await alerter.resolve("captcha-error-rate").catch(() => {});
}
}
}
const monitor = new CaptchaHealthMonitor();
// Run checks every 60 seconds
setInterval(() => monitor.checkAndAlert(), 60000);
module.exports = { monitor, alerter };
PagerDuty tarafını kurma: adım adım kontrol listesi
Kod tarafı hazır olduğunda geriye PagerDuty'yi yapılandırmak kalır. Aşağıdaki altı adım, yönlendirme anahtarını almaktan yükseltme politikasını kurmaya kadar tek seferlik hazırlığı kapsar.
| Adım | Eylem |
|---|---|
| 1 | "CaptchaAI Pipeline" için PagerDuty'de bir hizmet oluşturun |
| 2 | Hizmete Events API v2 entegrasyonunu ekleyin |
| 3 | Yönlendirme anahtarını PAGERDUTY_ROUTING_KEY ortam değişkenine kopyalayın |
| 4 | Yükseltme (escalation) politikasını ayarlayın: nöbetçi → ekip lideri → yönetici |
| 5 | Bildirim kurallarını yapılandırın (anlık bildirim, SMS, telefon) |
| 6 | Planlı bakımlar için bakım aralıkları (maintenance window) ekleyin |
Sorun giderme: uyarılar tetiklenmediğinde
Entegrasyonda en sık görülen dört sorun ve hızlı çözümleri aşağıda.
| Sorun | Sebep | Düzeltme |
|---|---|---|
| Uyarı tetiklenmiyor | Yanlış yönlendirme anahtarı | Anahtarın hizmetin Events API entegrasyonuyla eşleştiğini doğrulayın |
| Yinelenen olaylar | dedup_key eksik |
Her uyarı türü için tutarlı bir tekilleştirme anahtarı belirleyin |
| Uyarı seli | Tetikleyiciler arasında bekleme yok | PagerDuty aynı tekilleştirme anahtarına sahip kopyaları bastırır; anahtarı kullandığınızdan emin olun |
| Otomatik kapatma (auto-resolve) çalışmıyor | Tekilleştirme anahtarı uyuşmuyor | resolve çağrısının tetikleyiciyle tamamen aynı anahtarı kullandığından emin olun |
Türkiye'deki ekipler için pratik notlar
Türkiye'deki geliştirici ekiplerinin çoğu e-ticaret ve fintek tarafında yoğunlaşır; gece boyunca çalışan ödeme adımı ve checkout regresyon testleri, CAPTCHA çözüm hattının en sessiz saatlerde bile ayakta kalmasını gerektirir. Nöbet rotasyonunuzu Europe/Istanbul saat dilimine göre kurun ki uyarı, o an klavye başındaki kişiye ulaşsın.
Maliyet tarafında CaptchaAI'nin thread tabanlı planları öngörülebilirlik sağlar: BASIC ($15/ay, 5 thread) küçük bir izleme hattı için yeterken, yüksek hacimli işler VIP-3'e ($7,500/ay, 5.000 thread) kadar ölçeklenir. Fiyatlar USD üzerinden sabittir; TL'nin oynaklığı düşünüldüğünde bu, aylık bütçeyi tahmin etmeyi kolaylaştıran gerçek bir avantajdır. Hattınız kişisel veri işleyen kaynaklara dokunuyorsa KVKK yükümlülüklerini göz önünde bulundurun ve otomasyonu yalnızca yetkili QA ve veri toplama iş akışlarında çalıştırın.
Sık sorulan sorular
Bakiye uyarısı için hangi eşiği seçmeliyim?
Bu, günlük tüketiminize bağlıdır. Pratik kural: kritik eşiği kalan bakiyenin bir sonraki iş gününü çıkaramayacağı seviyeye, uyarı eşiğini ise rahatça yeniden yükleme yapacak kadar zaman tanıyan seviyeye koyun. Örnekteki $2 (kritik) ve $10 (uyarı) küçük bir hat için iyi bir başlangıçtır; hacim arttıkça bu sayıları yukarı çekin.
Hangi CaptchaAI metriklerini izlemeliyim?
En değerli üç sinyal bakiye, hata oranı ve worker durumudur. Bunlara getbalance ile çekilen bakiyeyi, kayan pencerede hesapladığınız çözüm hata oranını ve p95 çözüm gecikmesini ekleyin. Kuyruk derinliği de kapasite darboğazlarını erkenden gösterir.
Uyarı yorgunluğunu nasıl azaltırım?
İlgili tetikleyicileri tek bir olayda toplamak için dedup_key kullanın ve uyarı seviyesindeki bildirimleri düşük öncelikli (nöbetçiyi uyandırmayan) tutun. Kritik ve yüksek önceliği yalnızca bakiye < $2 ya da tüm worker'ların durması gibi gerçekten acil durumlara ayırın.
Aynı sorun için tekrar tekrar olay açılıyor; nasıl engellerim?
Neredeyse her zaman dedup_key eksikliğidir. Her uyarı türü için tutarlı bir tekilleştirme anahtarı belirleyin; PagerDuty aynı anahtara sahip yeni tetikleyicileri mevcut olayla birleştirir, durum düzeldiğinde resolve aynı anahtarla olayı otomatik kapatır.
PagerDuty yerine Datadog veya New Relic üzerinden yönlendirebilir miyim?
Evet. Hem Datadog hem de New Relic yerleşik PagerDuty entegrasyonlarına sahiptir. Metrikleri zaten bir gözlemlenebilirlik platformuna gönderiyorsanız uyarıları oradan yönlendirmek pratiktir. Buradaki doğrudan API entegrasyonu ise en fazla kontrolü istediğinizde en iyi seçenektir.
İlgili makaleler
- Müşteri projeleri için CAPTCHA çözüm hatları kurma
- Sorumlu otomasyonun ilkeleri
- Datadog metrik uyarılarıyla CaptchaAI izleme
Sonraki adımlar
CAPTCHA hattınız sorun yaşadığı anda haberdar olun: CaptchaAI API anahtarınızı alın ve PagerDuty'yi bağlayın.
İlgili kılavuzlar: