Hướng Dẫn Thực Hành

Cảnh báo Webhook của Discord về trạng thái quy trình CAPTCHA

Discord là nơi nhiều nhóm nhà phát triển đã giao tiếp. Thay vì xây dựng giao diện người dùng cảnh báo riêng biệt, hãy đẩy trực tiếp trạng thái quy trình CAPTCHA sang kênh Discord — các nội dung nhúng phong phú để cân bằng, lỗi và tóm tắt hàng ngày.

thiết lập

  1. Mở cài đặt máy chủ Discord của bạn
  2. Đi tới Tích hợp → Webhooks
  3. Nhấp vào Webhook mới và đặt tên là "Cảnh báo CaptchaAI"
  4. Sao chép URL webhook
  5. Lưu trữ dưới dạng biến môi trường DISCORD_WEBHOOK_URL

Python – Hệ thống cảnh báo Discord

import os
import time
import requests
from datetime import datetime

API_KEY = os.environ["CAPTCHAAI_API_KEY"]
DISCORD_WEBHOOK = os.environ["DISCORD_WEBHOOK_URL"]

session = requests.Session()

class DiscordCaptchaAlerts:
    COLORS = {
        "success": 0x2ECC71,   # Green
        "warning": 0xF39C12,   # Orange
        "error": 0xE74C3C,     # Red
        "info": 0x3498DB,      # Blue
    }

    def __init__(self, webhook_url):
        self.webhook_url = webhook_url

    def send_embed(self, title, description, color_key="info", fields=None):
        embed = {
            "title": title,
            "description": description,
            "color": self.COLORS.get(color_key, self.COLORS["info"]),
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "footer": {"text": "CaptchaAI Pipeline Monitor"}
        }
        if fields:
            embed["fields"] = fields

        payload = {"embeds": [embed]}
        resp = requests.post(
            self.webhook_url, json=payload, timeout=10
        )
        resp.raise_for_status()

    def balance_alert(self, balance, threshold):
        severity = "error" if balance < 2 else "warning"
        self.send_embed(
            title="💰 Balance Alert",
            description=f"CaptchaAI balance is **${balance:.2f}**",
            color_key=severity,
            fields=[
                {"name": "Threshold", "value": f"${threshold:.2f}", "inline": True},
                {"name": "Severity", "value": severity.upper(), "inline": True},
                {"name": "Action", "value": "Top up your balance at captchaai.com", "inline": False}
            ]
        )

    def error_spike(self, error_rate, error_count, total_count, top_errors):
        error_list = "\n".join(
            f"• `{code}`: {count}" for code, count in top_errors.items()
        )
        self.send_embed(
            title="⚠️ Error Rate Spike",
            description=f"Error rate: **{error_rate:.1%}** ({error_count}/{total_count})",
            color_key="error",
            fields=[
                {"name": "Error Breakdown", "value": error_list or "No details", "inline": False},
                {"name": "Window", "value": "Last 5 minutes", "inline": True}
            ]
        )

    def queue_alert(self, depth, workers_active):
        self.send_embed(
            title="📊 Queue Backup",
            description=f"Queue depth: **{depth}** pending tasks",
            color_key="warning",
            fields=[
                {"name": "Active Workers", "value": str(workers_active), "inline": True},
                {"name": "Est. Drain Time", "value": f"{depth // max(workers_active, 1)} min", "inline": True}
            ]
        )

    def daily_summary(self, stats):
        self.send_embed(
            title="📈 Daily CAPTCHA Summary",
            description=f"**{stats['total']}** tasks processed",
            color_key="success" if stats["success_rate"] > 0.92 else "warning",
            fields=[
                {"name": "Success Rate", "value": f"{stats['success_rate']:.1%}", "inline": True},
                {"name": "Avg Latency", "value": f"{stats['avg_latency']:.1f}s", "inline": True},
                {"name": "Total Cost", "value": f"${stats['cost']:.2f}", "inline": True},
                {"name": "Errors", "value": str(stats["errors"]), "inline": True},
                {"name": "Balance", "value": f"${stats['balance']:.2f}", "inline": True},
                {"name": "Peak Queue", "value": str(stats["peak_queue"]), "inline": True},
            ]
        )

    def solve_recovered(self, previous_rate, current_rate):
        self.send_embed(
            title="✅ Pipeline Recovered",
            description=f"Solve rate recovered: {previous_rate:.1%} → {current_rate:.1%}",
            color_key="success"
        )

alerts = DiscordCaptchaAlerts(DISCORD_WEBHOOK)

class PipelineMonitor:
    def __init__(self, check_interval=60):
        self.check_interval = check_interval
        self.results = []  # (timestamp, success, error_code)
        self.last_balance_alert = 0
        self.last_error_alert = 0
        self.cooldown = 300  # 5 minutes between alerts

    def record(self, success, error_code=None):
        self.results.append((time.time(), success, error_code))
        # Keep last 5 min
        cutoff = time.time() - 300
        self.results = [r for r in self.results if r[0] > cutoff]

    def run_checks(self):
        now = time.time()

        # Balance check
        if now - self.last_balance_alert > self.cooldown:
            balance = self._check_balance()
            if balance is not None and balance < 10:
                alerts.balance_alert(balance, threshold=10)
                self.last_balance_alert = now

        # Error rate check
        if now - self.last_error_alert > self.cooldown and len(self.results) > 10:
            total = len(self.results)
            errors = [r for r in self.results if not r[1]]
            error_rate = len(errors) / total

            if error_rate > 0.15:
                error_breakdown = {}
                for _, _, code in errors:
                    if code:
                        error_breakdown[code] = error_breakdown.get(code, 0) + 1
                alerts.error_spike(error_rate, len(errors), total, error_breakdown)
                self.last_error_alert = now

    def _check_balance(self):
        try:
            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 float(data["request"])
        except Exception:
            pass
        return None

monitor = PipelineMonitor()

JavaScript – Máy khách Webhook Discord

const axios = require("axios");

const API_KEY = process.env.CAPTCHAAI_API_KEY;
const DISCORD_WEBHOOK = process.env.DISCORD_WEBHOOK_URL;

const COLORS = {
  success: 0x2ecc71,
  warning: 0xf39c12,
  error: 0xe74c3c,
  info: 0x3498db,
};

async function sendDiscordEmbed(title, description, colorKey = "info", fields = []) {
  await axios.post(DISCORD_WEBHOOK, {
    embeds: [
      {
        title,
        description,
        color: COLORS[colorKey] || COLORS.info,
        timestamp: new Date().toISOString(),
        footer: { text: "CaptchaAI Pipeline Monitor" },
        fields,
      },
    ],
  }, { timeout: 10000 });
}

async function alertBalance(balance, threshold = 10) {
  const severity = balance < 2 ? "error" : "warning";
  await sendDiscordEmbed(
    "💰 Balance Alert",
    `CaptchaAI balance is **$${balance.toFixed(2)}**`,
    severity,
    [
      { name: "Threshold", value: `$${threshold.toFixed(2)}`, inline: true },
      { name: "Severity", value: severity.toUpperCase(), inline: true },
    ]
  );
}

async function alertErrorSpike(errorRate, details = {}) {
  await sendDiscordEmbed(
    "⚠️ Error Rate Spike",
    `Error rate: **${(errorRate * 100).toFixed(1)}%**`,
    "error",
    [
      { name: "Total Tasks", value: String(details.total || 0), inline: true },
      { name: "Errors", value: String(details.errors || 0), inline: true },
    ]
  );
}

async function sendDailySummary(stats) {
  const color = stats.successRate > 0.92 ? "success" : "warning";
  await sendDiscordEmbed(
    "📈 Daily CAPTCHA Summary",
    `**${stats.total}** tasks processed`,
    color,
    [
      { name: "Success Rate", value: `${(stats.successRate * 100).toFixed(1)}%`, inline: true },
      { name: "Avg Latency", value: `${stats.avgLatency.toFixed(1)}s`, inline: true },
      { name: "Balance", value: `$${stats.balance.toFixed(2)}`, inline: true },
    ]
  );
}

// Balance monitoring loop
async function monitorBalance() {
  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 < 10) await alertBalance(balance);
    }
  } catch (err) {
    console.error("Balance check failed:", err.message);
  }
}

setInterval(monitorBalance, 300000); // Every 5 minutes

module.exports = { alertBalance, alertErrorSpike, sendDailySummary };

Ví dụ về tin nhắn Discord

Cảnh báo số dư:

💰 Cảnh báo số dư Số dư CaptchaAI là $8,42 Ngưỡng: $10,00 | Mức độ nghiêm trọng: CẢNH BÁO

Lỗi tăng đột biến:

⚠️ Tỷ lệ lỗi tăng đột biến Tỷ lệ lỗi: 22,5% (45/200) ™ ERROR_CAPTCHA_UNSOLVABLE: 30 ™ TIMEOUT: 15

Tóm tắt hàng ngày:

📈 Tóm tắt CAPTCHA hàng ngày 12.450 nhiệm vụ được xử lý Tỷ lệ thành công: 95,2% | Độ trễ trung bình: 22,4 giây | Số dư: $142,30

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
400 yêu cầu xấu Cấu trúc nhúng không hợp lệ Kiểm tra định dạng mảng trường; đảm bảo tất cả các giá trị là chuỗi
Tỷ lệ giới hạn (429) Quá nhiều tin nhắn mỗi phút Thêm thời gian hồi chiêu giữa các cảnh báo (tối thiểu 5 phút)
Đã xóa webhook Ai đó đã xóa nó khỏi máy chủ Tạo một webhook mới; cập nhật env var
Nhúng không hiển thị Thiếu mảng embeds Gói đối tượng nhúng trong {"embeds": [...]}

Câu hỏi thường gặp

Tôi có thể có bao nhiêu webhooks Discord cho mỗi kênh?

15 mỗi kênh. Tạo một webhook cho CaptchaAI và sử dụng lại nó cho tất cả các loại cảnh báo.

Tôi có thể @mention người dùng hoặc vai trò trong cảnh báo không?

Vâng. Thêm "content": "<@USER_ID>" hoặc "content": "<@&ROLE_ID>" vào tải trọng webhook để nhận các cảnh báo quan trọng.

Tôi có nên sử dụng Discord để cảnh báo sản xuất không?

Discord hoạt động tốt như một kênh thông báo phụ. Để phân trang theo cuộc gọi, hãy sử dụng PagerDuty hoặc Opsgenie. Về khả năng hiển thị của nhóm, Discord rất tuyệt vời.

Các bước tiếp theo

Nhận thông báo đường ống nơi nhóm của bạn đã sống —bắt đầu với khóa API CaptchaAIvà kết nối với Discord.

Hướng dẫn liên quan:

Os comentários estão desativados para este artigo.