DevOps & Scaling

Monitoring CaptchaAI dengan New Relic: Integrasi APM

Ketika sebuah solve CAPTCHA melambat atau gagal di production, Anda perlu tahu penyebabnya dalam hitungan menit — bukan setelah task scraping menumpuk atau klien mengeluh. Jawabannya adalah instrumentation yang tepat: dengan beberapa baris kode, setiap task yang Anda kirim ke CaptchaAI — dari submit, polling, hingga token dipakai — terekam di New Relic sebagai transaksi dan custom event yang bisa Anda filter per jenis CAPTCHA. Panduan ini menunjukkan cara memasang instrumentation itu di Python dan Node.js, membangun dashboard NRQL, lalu menyiapkan alert sebelum masalah menyebar.

Metrik yang perlu dipantau di setiap fase solve

Sebuah solve CAPTCHA bukan satu titik, melainkan tiga fase berurutan, dan tiap fase punya sinyal kesehatannya sendiri. Kalau Anda hanya melihat "berhasil atau gagal" di ujung, Anda kehilangan konteks untuk membedakan submit yang lambat dari antrean polling yang macet. Petakan dulu apa yang diukur di masing-masing fase:

[Submit Task] → [Wait for Solution] → [Apply Token]
     ↓                  ↓                   ↓
  Submit latency    Poll duration       Token usage
  API errors        Timeout rate        Success rate

Submit latency menunjukkan seberapa cepat task diterima, durasi polling menunjukkan berapa lama worker menunggu, dan tingkat keberhasilan di fase akhir adalah metrik bisnis yang benar-benar Anda pedulikan.

Instrumentation New Relic di Python

Mulai dari sisi Python, karena mayoritas worker scraping di komunitas otomasi Indonesia berjalan di sini. Pola intinya: bungkus alur solve sebagai background task, tambahkan custom attribute agar bisa difilter per jenis CAPTCHA, lalu catat custom event terpisah untuk sukses dan error. Dengan begitu Anda bisa memisahkan kegagalan di fase submit dari kegagalan di fase polling — dua akar masalah yang berbeda.

import os
import time
import requests
import newrelic.agent

API_KEY = os.environ["CAPTCHAAI_API_KEY"]
session = requests.Session()


@newrelic.agent.background_task(name="captcha_solve", group="CaptchaAI")
def solve_captcha(sitekey, pageurl, captcha_type="recaptcha_v2"):
    """Solve a CAPTCHA with full New Relic instrumentation."""
    # Add custom attributes for filtering
    newrelic.agent.add_custom_attributes([
        ("captcha_type", captcha_type),
        ("target_url", pageurl),
    ])

    # Submit phase
    submit_result = _submit_task(sitekey, pageurl, captcha_type)
    if "error" in submit_result:
        newrelic.agent.record_custom_event("CaptchaSolveError", {
            "error": submit_result["error"],
            "phase": "submit",
            "captcha_type": captcha_type,
        })
        return submit_result

    # Poll phase
    captcha_id = submit_result["captcha_id"]
    poll_result = _poll_result(captcha_id, captcha_type)

    # Record solve event
    event_data = {
        "captcha_type": captcha_type,
        "captcha_id": captcha_id,
        "success": "solution" in poll_result,
    }
    if "solution" in poll_result:
        event_data["solve_time"] = poll_result.get("elapsed", 0)
        newrelic.agent.record_custom_event("CaptchaSolveSuccess", event_data)
    else:
        event_data["error"] = poll_result.get("error", "unknown")
        newrelic.agent.record_custom_event("CaptchaSolveError", event_data)

    return poll_result


@newrelic.agent.function_trace(name="captcha_submit")
def _submit_task(sitekey, pageurl, captcha_type):
    payload = {
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1
    }
    resp = session.post("https://ocr.captchaai.com/in.php", data=payload)
    data = resp.json()

    newrelic.agent.add_custom_attributes([
        ("submit_status", data.get("status")),
    ])

    if data.get("status") != 1:
        return {"error": data.get("request")}
    return {"captcha_id": data["request"]}


@newrelic.agent.function_trace(name="captcha_poll")
def _poll_result(captcha_id, captcha_type):
    start = time.time()
    poll_count = 0

    for _ in range(60):
        time.sleep(5)
        poll_count += 1
        result = session.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": captcha_id, "json": 1
        }).json()

        if result.get("status") == 1:
            elapsed = time.time() - start
            newrelic.agent.add_custom_attributes([
                ("poll_count", poll_count),
                ("solve_time_seconds", round(elapsed, 2)),
            ])
            return {"solution": result["request"], "elapsed": elapsed}

        if result.get("request") != "CAPCHA_NOT_READY":
            return {"error": result.get("request")}

    return {"error": "TIMEOUT"}


def report_balance():
    """Record balance as a custom event."""
    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:
        balance = float(data["request"])
        newrelic.agent.record_custom_event("CaptchaBalance", {
            "balance": balance,
            "low": balance < 10,
        })
        return balance
    return None

Perhatikan function_trace pada _submit_task dan _poll_result: keduanya memecah satu transaksi menjadi span terpisah, sehingga di waterfall New Relic Anda langsung terlihat apakah waktu terbuang saat submit atau saat menunggu hasil.

Konfigurasi agent New Relic

Custom event tidak akan muncul kalau custom_insights_events mati. Naikkan juga max_samples_stored bila volume solve Anda tinggi, agar sampel tidak terpotong pada jam sibuk:

# newrelic.ini
[newrelic]
app_name = CaptchaAI Pipeline
license_key = YOUR_NEW_RELIC_LICENSE_KEY
monitor_mode = true
log_level = info
transaction_tracer.enabled = true
transaction_tracer.transaction_threshold = 5.0
custom_insights_events.enabled = true
custom_insights_events.max_samples_stored = 5000

Instrumentation New Relic di Node.js

Untuk worker berbasis Node.js — misalnya pipeline Puppeteer atau Playwright — polanya setara. Bungkus solve dengan startBackgroundTransaction, tambahkan custom attribute, dan catat CaptchaSolveSuccess atau CaptchaSolveError sesuai hasil. Nama event dijaga persis sama dengan versi Python agar satu query NRQL bisa menggabungkan metrik dari worker Python dan Node.js sekaligus.

const newrelic = require("newrelic");
const axios = require("axios");

const API_KEY = process.env.CAPTCHAAI_API_KEY;

async function solveCaptchaWithNewRelic(sitekey, pageurl, captchaType = "recaptcha_v2") {
  return newrelic.startBackgroundTransaction(
    "CaptchaSolve",
    "CaptchaAI",
    async () => {
      const transaction = newrelic.getTransaction();
      newrelic.addCustomAttributes({
        captchaType,
        targetUrl: pageurl,
      });

      const startTime = Date.now();

      try {
        // Submit
        const submitResp = await axios.post(
          "https://ocr.captchaai.com/in.php",
          null,
          {
            params: {
              key: API_KEY,
              method: "userrecaptcha",
              googlekey: sitekey,
              pageurl: pageurl,
              json: 1,
            },
          }
        );

        if (submitResp.data.status !== 1) {
          newrelic.recordCustomEvent("CaptchaSolveError", {
            error: submitResp.data.request,
            phase: "submit",
            captchaType,
          });
          transaction.end();
          return { error: submitResp.data.request };
        }

        const captchaId = submitResp.data.request;
        newrelic.addCustomAttributes({ captchaId });

        // Poll
        let pollCount = 0;
        for (let i = 0; i < 60; i++) {
          await new Promise((r) => setTimeout(r, 5000));
          pollCount++;

          const pollResp = await axios.get(
            "https://ocr.captchaai.com/res.php",
            {
              params: {
                key: API_KEY, action: "get", id: captchaId, json: 1,
              },
            }
          );

          if (pollResp.data.status === 1) {
            const elapsed = (Date.now() - startTime) / 1000;
            newrelic.recordCustomEvent("CaptchaSolveSuccess", {
              captchaType,
              solveTime: elapsed,
              pollCount,
            });
            newrelic.addCustomAttributes({
              solveTime: elapsed,
              pollCount,
            });
            transaction.end();
            return { solution: pollResp.data.request, elapsed };
          }

          if (pollResp.data.request !== "CAPCHA_NOT_READY") {
            newrelic.recordCustomEvent("CaptchaSolveError", {
              error: pollResp.data.request,
              phase: "poll",
              captchaType,
            });
            transaction.end();
            return { error: pollResp.data.request };
          }
        }

        newrelic.recordCustomEvent("CaptchaSolveError", {
          error: "TIMEOUT",
          phase: "poll",
          captchaType,
          pollCount,
        });
        transaction.end();
        return { error: "TIMEOUT" };
      } catch (err) {
        newrelic.noticeError(err);
        transaction.end();
        throw err;
      }
    }
  );
}

// Balance monitoring
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);
      newrelic.recordCustomEvent("CaptchaBalance", { balance });
    }
  } catch (err) {
    newrelic.noticeError(err);
  }
}

setInterval(monitorBalance, 60000);

module.exports = { solveCaptchaWithNewRelic };

Dashboard NRQL untuk solve rate dan latency

Setelah event mengalir, semua analitik dilakukan lewat NRQL. Enam query di bawah cukup untuk satu dashboard operasional: tingkat keberhasilan, waktu penyelesaian per jenis CAPTCHA, rincian error, P95 latency, tren saldo, dan throughput per menit.

-- Solve success rate (last hour)
SELECT percentage(count(*), WHERE success = true)
FROM CaptchaSolveSuccess, CaptchaSolveError
SINCE 1 hour ago

-- Average solve time by CAPTCHA type
SELECT average(solveTime)
FROM CaptchaSolveSuccess
FACET captchaType
SINCE 1 hour ago TIMESERIES

-- Error breakdown
SELECT count(*)
FROM CaptchaSolveError
FACET error
SINCE 1 hour ago

-- P95 solve latency
SELECT percentile(solveTime, 95)
FROM CaptchaSolveSuccess
SINCE 1 hour ago TIMESERIES

-- Balance over time
SELECT latest(balance)
FROM CaptchaBalance
SINCE 24 hours ago TIMESERIES 5 minutes

-- Tasks per minute
SELECT rate(count(*), 1 minute)
FROM CaptchaSolveSuccess, CaptchaSolveError
SINCE 1 hour ago TIMESERIES

Pantau P95, bukan hanya rata-rata: rata-rata bisa tampak sehat sementara sebagian kecil task tersangkut dan menghabiskan slot thread. Untuk worker yang deploy di region terdekat seperti AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta), FACET captchaType memisahkan latency jaringan dari waktu solve sebenarnya.

Alert policy yang perlu Anda siapkan

Dashboard menjawab "sedang terjadi apa"; alert menjawab "kapan saya harus turun tangan". Empat kondisi ini menutup kasus paling umum di pipeline solve:

Alert Kondisi NRQL Threshold
Solve rate turun SELECT percentage(count(*), WHERE success = true) <85% selama 5 menit
Latency tinggi SELECT percentile(solveTime, 95) FROM CaptchaSolveSuccess > 120 detik selama 10 menit
Saldo menipis SELECT latest(balance) FROM CaptchaBalance < $10
Lonjakan error SELECT count(*) FROM CaptchaSolveError > 50 dalam 5 menit

Contoh nyata: sebuah agensi price-monitoring yang menjalankan solve konkuren di paket PREMIUM ($170/bulan, 100 threads) memakai alert "solve rate turun" untuk menangkap perubahan sitekey di situs target lebih dulu, sebelum data harian mereka bolong. Karena CaptchaAI menagih per thread dengan solve tak terbatas per thread, alert yang berguna bukan soal biaya per task, melainkan soal berapa banyak thread yang tersita oleh task yang lambat atau gagal.

Mengatasi masalah umum integrasi New Relic

Kalau data tidak muncul seperti yang diharapkan, mulai dari empat penyebab tersering ini sebelum menggali lebih dalam:

Masalah Penyebab Solusi
Custom event tidak muncul custom_insights_events.enabled bernilai salah Aktifkan di newrelic.ini
Transaction trace hilang Threshold terlalu tinggi Turunkan transaction_threshold ke 1.0 detik
Atribut terpotong Nilai atribut terlalu panjang Jaga nilai atribut di bawah 255 karakter
Tidak ada data setelah deploy License key salah atau agent tidak start Jalankan newrelic-admin validate-config newrelic.ini

Pertanyaan umum

Metrik CaptchaAI mana yang sebaiknya saya pantau lebih dulu?

Mulai dari tiga: tingkat keberhasilan (CaptchaSolveSuccess vs CaptchaSolveError), P95 waktu penyelesaian, dan rincian error per kode. Ketiganya langsung menjawab "apakah pipeline sehat" dan "kalau tidak, di fase mana". Metrik lain seperti tasks per minute berguna untuk kapasitas, tetapi bukan yang pertama Anda butuhkan saat insiden.

Apakah versi gratis New Relic cukup untuk memantau CaptchaAI?

Untuk satu worker atau proyek kecil, tier gratis New Relic biasanya memadai karena custom event dan NRQL tersedia di paket dasar. Yang perlu Anda cek adalah kuota data bulanan dan retensi query — pada volume solve tinggi, max_samples_stored dan jumlah event yang tercatat bisa menyentuh batas. Ini keputusan tentang paket New Relic, bukan tentang CaptchaAI; harga paket CaptchaAI ditagih terpisah per thread.

Bagaimana cara memantau saldo agar thread tidak berhenti di tengah scraping?

Fungsi report_balance / monitorBalance mengirim event CaptchaBalance secara berkala, dan alert "saldo menipis" di < $10 memberi Anda waktu bertindak sebelum task tertahan. Untuk pipeline yang berjalan semalaman, jalankan pengecekan tiap 60 detik seperti contoh setInterval dan kirim notifikasi ke channel tim.

Seberapa besar overhead New Relic terhadap waktu solve?

Dapat diabaikan. Agent hanya menambah overhead dalam skala mikrodetik per call yang diinstrumentasi, sementara waktu solve CAPTCHA berkisar 5–120 detik. Selisihnya tidak terukur dalam praktik, jadi instrumentation tidak akan memperlambat pipeline.


Artikel Terkait


Dapatkan visibilitas menyeluruh atas pipeline CAPTCHA Anda — mulai dengan API key CaptchaAI lalu hubungkan ke New Relic.

Komentar dinonaktifkan untuk artikel ini.