CAPTCHA çözme çalışanınız canlı görünüyor - süreç çalışıyor - ancak 10 dakika içinde bir görevi başarıyla çözmedi. API anahtarı tükendi veya çalışan bir döngüde kaldı. Durum kontrolleri olmadan orkestratörünüz işi ölü bir çalışana yönlendirmeye devam eder. Sağlık uç noktaları, yük dengeleyicilerin ve Kubernetes'in sorunu tespit etmesine ve yeniden yönlendirmesine olanak tanır.
Üç Tür Sağlık Kontrolü
| Kontrol et | Soru | Arıza yanıtı |
|---|---|---|
| Canlılık | Süreç yürüyor mu? | Kapsayıcıyı yeniden başlatın |
| Hazırlık | İşi kabul edebilir mi? | Trafiği yönlendirmeyi durdurun |
| Bağımlılık | Yukarı akış hizmetleri iyi mi? | İncelikle bozun |
Python: Flask Sağlığı Uç Noktaları
import requests
import time
import threading
from flask import Flask, jsonify
from dataclasses import dataclass, field
API_KEY = "YOUR_API_KEY"
RESULT_URL = "https://ocr.captchaai.com/res.php"
app = Flask(__name__)
@dataclass
class WorkerHealth:
"""Tracks worker health metrics."""
started_at: float = field(default_factory=time.monotonic)
last_solve_at: float = 0.0
total_solved: int = 0
total_failed: int = 0
consecutive_failures: int = 0
balance: float | None = None
balance_checked_at: float = 0.0
_lock: threading.Lock = field(default_factory=threading.Lock)
def record_success(self):
with self._lock:
self.total_solved += 1
self.last_solve_at = time.monotonic()
self.consecutive_failures = 0
def record_failure(self):
with self._lock:
self.total_failed += 1
self.consecutive_failures += 1
@property
def success_rate(self) -> float:
total = self.total_solved + self.total_failed
return self.total_solved / total if total > 0 else 1.0
@property
def seconds_since_last_solve(self) -> float:
if self.last_solve_at == 0:
return time.monotonic() - self.started_at
return time.monotonic() - self.last_solve_at
health = WorkerHealth()
# Thresholds
MAX_CONSECUTIVE_FAILURES = 10
MAX_SECONDS_WITHOUT_SOLVE = 600 # 10 minutes
MIN_BALANCE = 1.0
def check_balance() -> float | None:
"""Check CaptchaAI balance."""
now = time.monotonic()
# Cache balance for 60 seconds
if health.balance is not None and now - health.balance_checked_at < 60:
return health.balance
try:
resp = requests.get(RESULT_URL, params={
"key": API_KEY, "action": "getbalance", "json": 1,
}, timeout=10).json()
health.balance = float(resp.get("request", 0))
health.balance_checked_at = now
return health.balance
except Exception:
return health.balance # Return cached value on error
@app.route("/health/live")
def liveness():
"""Liveness probe — is the process responsive?"""
return jsonify({"status": "ok", "uptime_s": int(time.monotonic() - health.started_at)}), 200
@app.route("/health/ready")
def readiness():
"""Readiness probe — can the worker accept tasks?"""
issues = []
# Check consecutive failures
if health.consecutive_failures >= MAX_CONSECUTIVE_FAILURES:
issues.append(f"consecutive_failures={health.consecutive_failures}")
# Check time since last solve
if health.total_solved > 0 and health.seconds_since_last_solve > MAX_SECONDS_WITHOUT_SOLVE:
issues.append(f"no_solve_for={int(health.seconds_since_last_solve)}s")
# Check balance
balance = check_balance()
if balance is not None and balance < MIN_BALANCE:
issues.append(f"low_balance=${balance:.2f}")
if issues:
return jsonify({
"status": "not_ready",
"issues": issues,
"stats": {
"solved": health.total_solved,
"failed": health.total_failed,
"success_rate": round(health.success_rate, 3),
},
}), 503
return jsonify({
"status": "ready",
"stats": {
"solved": health.total_solved,
"failed": health.total_failed,
"success_rate": round(health.success_rate, 3),
"balance": balance,
},
}), 200
@app.route("/health/dependencies")
def dependencies():
"""Check upstream dependencies."""
checks = {}
# CaptchaAI API reachability
try:
resp = requests.get(RESULT_URL, params={
"key": API_KEY, "action": "getbalance", "json": 1,
}, timeout=10)
checks["captchaai_api"] = {
"status": "ok" if resp.status_code == 200 else "degraded",
"response_ms": int(resp.elapsed.total_seconds() * 1000),
}
except Exception as e:
checks["captchaai_api"] = {"status": "down", "error": str(e)}
all_ok = all(c["status"] == "ok" for c in checks.values())
return jsonify({
"status": "ok" if all_ok else "degraded",
"checks": checks,
}), 200 if all_ok else 503
# --- Worker loop (runs in background) ---
def worker_loop():
"""Simulated CAPTCHA solving worker."""
while True:
try:
# ... solve CAPTCHA logic ...
health.record_success()
except Exception:
health.record_failure()
time.sleep(1)
threading.Thread(target=worker_loop, daemon=True).start()
JavaScript: Ekspres Sağlık Uç Noktaları
const express = require("express");
const API_KEY = "YOUR_API_KEY";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
const app = express();
const health = {
startedAt: Date.now(),
lastSolveAt: 0,
totalSolved: 0,
totalFailed: 0,
consecutiveFailures: 0,
balance: null,
balanceCheckedAt: 0,
recordSuccess() {
this.totalSolved++;
this.lastSolveAt = Date.now();
this.consecutiveFailures = 0;
},
recordFailure() {
this.totalFailed++;
this.consecutiveFailures++;
},
get successRate() {
const total = this.totalSolved + this.totalFailed;
return total > 0 ? this.totalSolved / total : 1;
},
};
async function checkBalance() {
if (health.balance !== null && Date.now() - health.balanceCheckedAt < 60000) {
return health.balance;
}
try {
const url = `${RESULT_URL}?key=${API_KEY}&action=getbalance&json=1`;
const resp = await (await fetch(url)).json();
health.balance = parseFloat(resp.request);
health.balanceCheckedAt = Date.now();
return health.balance;
} catch {
return health.balance;
}
}
app.get("/health/live", (req, res) => {
res.json({ status: "ok", uptimeMs: Date.now() - health.startedAt });
});
app.get("/health/ready", async (req, res) => {
const issues = [];
if (health.consecutiveFailures >= 10) {
issues.push(`consecutive_failures=${health.consecutiveFailures}`);
}
if (health.totalSolved > 0) {
const silentMs = Date.now() - health.lastSolveAt;
if (silentMs > 600_000) {
issues.push(`no_solve_for=${Math.round(silentMs / 1000)}s`);
}
}
const balance = await checkBalance();
if (balance !== null && balance < 1.0) {
issues.push(`low_balance=$${balance.toFixed(2)}`);
}
const stats = {
solved: health.totalSolved,
failed: health.totalFailed,
successRate: Math.round(health.successRate * 1000) / 1000,
balance,
};
if (issues.length > 0) {
return res.status(503).json({ status: "not_ready", issues, stats });
}
res.json({ status: "ready", stats });
});
app.get("/health/dependencies", async (req, res) => {
const checks = {};
try {
const start = Date.now();
const url = `${RESULT_URL}?key=${API_KEY}&action=getbalance&json=1`;
const resp = await fetch(url);
checks.captchaaiApi = {
status: resp.ok ? "ok" : "degraded",
responseMs: Date.now() - start,
};
} catch (e) {
checks.captchaaiApi = { status: "down", error: e.message };
}
const allOk = Object.values(checks).every((c) => c.status === "ok");
res.status(allOk ? 200 : 503).json({
status: allOk ? "ok" : "degraded",
checks,
});
});
app.listen(8080, () => console.log("Health server on :8080"));
Kubernetes Yapılandırması
apiVersion: apps/v1
kind: Deployment
metadata:
name: captcha-worker
spec:
replicas: 3
template:
spec:
containers:
- name: worker
image: captcha-worker:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 2
Durum Denetimi Yanıt Kodları
| Uç nokta | 200 | 503 |
|---|---|---|
/health/live |
Süreç duyarlı | İşlem donduruldu - yeniden başlat |
/health/ready |
İşi kabul edebilir | Görev göndermeyi durdur |
/health/dependencies |
Tüm bağımlılıklar tamam | Yukarı akış bozulmuş |
Operatör eşikleri
- Yeni çalışmayı engellemek için hazır olma durumunu, yeniden başlatmayı tetiklemek için canlılığı ve düşen verimi yakalamak için uyarıları dengelemeyi kullanın.
- Durum denetimlerini yalnızca sürecin çalışma süresi yerine kuyruk derinliğine, son hata oranına ve bağımlılığa erişilebilirliğe bağlayın.
- Durum değişikliklerinin gürültülü değil eyleme geçirilebilir olmasını sağlamak için eşik değerlerini çağrı sırasında yanıt verenler için görünür tutun.
Sorun giderme
| Sorun | Sebep | Düzeltme |
|---|---|---|
| İşçi sürekli olarak yeniden başlatıldı | Canlılık eşiği çok düşük | failureThreshold veya periodSeconds'yi artırın |
| Çalışan başlatma sırasında hazır değil olarak işaretlendi | Henüz "çok uzun" olarak sayılan bir çözüm yok | seconds_since_last_solve'yi yalnızca ilk çözümden sonra kontrol edin |
| Denge kontrolü sağlık uç noktasını yavaşlatır | Her istekte API çağrısı | Bakiyeyi bir TTL ile önbelleğe alın (60 saniye önerilir) |
| Sağlık uç noktasının kendisi çöküyor | Kontrolde işlenmeyen istisna | Her kontrolü try/except'ye sarın; 500 yerine düşük getiri |
| Bağımlılık kontrolünden kaynaklanan hatalı negatifler | Denge kontrolü sırasında ağ kesintisi | Önbelleğe alınmış değerleri, eskimişken yeniden doğrulama yaklaşımıyla kullanın |
SSS
Kubernetes'in sağlık uç noktalarını ne sıklıkla araştırması gerekir?
Canlılık: 3'lük bir hata eşiğiyle her 10-30 saniyede bir. Hazırlık: 2'lik bir hata eşiğiyle her 5-10 saniyede bir. Daha sık yapılan incelemeler sorunları daha hızlı algılar ancak ek yük getirir.
Sistem durumu uç noktası CaptchaAI API'sine mi çarpmalı?
Yalnızca hazırlık ve bağımlılık kontrolleri için ve sonucu her zaman önbelleğe alın. Canlılık araştırması asla harici çağrılar yapmamalı; sürecin canlı olduğunu kanıtlamak için anında yanıt vermelidir.
Birden fazla çalışanın sağlığını nasıl izlerim?
Sistem durumu ölçümlerini, sistem durumu uç noktalarının yanı sıra Prometheus biçiminde (/metrics) gösterin. Filo genelindeki durumu görmek için Grafana kontrol panelleriyle çalışanlar arasında bir araya gelin.
İlgili Makaleler
Sonraki Adımlar
CAPTCHA çalışanlarınızı üretime hazır hale getirin —CaptchaAI API anahtarınızı alınve durum denetimi uç noktaları ekleyin.
İlgili kılavuzlar: