Web Scraping & Agen

Memperbaiki Error HTTP 429 dan Cloudflare 520 pada AI Crawler dan Agen

Jawaban Cepat: Error HTTP 429 menunjukkan pelanggaran batas frekuensi (rate limit) pada API target atau WAF, yang dapat diselesaikan dengan backoff Decorrelated Jitter dan pool proxy residensial berotasi. Error Cloudflare 520 ("Web Server Returned an Unknown Error") terjadi ketika server asal mengalami crash, reset TCP RST, atau overflow header di bawah beban scraping yang berat.

1. Pendahuluan: Kerentanan Web Crawler AI Otonom

Seiring berkembangnya agen AI otonom dari antarmuka percakapan menjadi mesin penalaran multi-langkah (riset web langsung, uji kelayakan finansial, pemantauan kompetitor), hambatan utama bukan lagi kecepatan komputasi LLM, melainkan keandalan jaringan dan akses Edge.

Sistem agen modern mengeksekusi ribuan panggilan HTTP per menit. Tidak seperti crawler konvensional (Scrapy, Googlebot), agen AI membutuhkan:

  1. Pengambilan data sinkron berlatensi rendah agar tidak memutus penalaran (reasoning loop).
  2. Eksekusi JavaScript mendalam untuk me-render aplikasi SPA.
  3. Konversi Markdown yang bersih untuk menghemat token konteks.

Namun, infrastruktur Edge seperti Cloudflare dan DataDome memasang proteksi ketat yang memicu dua error utama:

  • HTTP 429 Too Many Requests: Batas permintaan terlampaui.
  • HTTP 520 Web Server Returned an Unknown Error: Server asal gagal memberikan respons yang valid kepada Cloudflare.

2. Anatomi HTTP 429: Rate Limit dan TLS Fingerprint

Sesuai RFC 6585, error 429 terjadi di tiga tingkatan:

  1. Tingkat 1: Edge WAF (Cloudflare / DataDome): Menangkap ketidakcocokan antara JA4 TLS fingerprint (misalnya Python OpenSSL) dan User-Agent yang dikirimkan (Chrome), memicu 429 atau CAPTCHA.
  2. Tingkat 2: API Gateway (Kong, Envoy, Nginx): Pembatasan Token Bucket dan Leaky Bucket.
  3. Tingkat 3: Server Aplikasi: Proteksi terhadap kehabisan koneksi database atau CPU.

Header respons penting: Retry-After, RateLimit-Limit, RateLimit-Remaining, dan RateLimit-Reset.


3. Memahami Error Cloudflare 520

Error 520 merupakan kode status khusus Cloudflare yang menunjukkan kegagalan pada server asal:

  1. Worker Crash (OOM / SIGSEGV): Beban crawling masif menghabiskan memori server asal sehingga proses terhenti mendadak dan mengirim TCP RST ke Cloudflare.
  2. Ketidaksesuaian Keep-Alive: Cloudflare menahan koneksi 15 detik. Jika Nginx memutus pada detik ke-5, request yang lewat akan terputus dengan error 520.
  3. Header Terlalu Besar (>16KB): Perulangan Set-Cookie berlebih melebihi batas buffer Edge.
  4. Respons Kosong (Nol Byte): Server menutup soket tanpa mengirimkan data apapun.

4. Solusi Algoritma: Decorrelated Jitter dan Circuit Breaker

Perulangan retry sederhana memicu fenomena Thundering Herd. Solusi terbaik yang divalidasi oleh arsitektur AWS adalah Decorrelated Jitter:

# Formula Decorrelated Jitter:
sleep = min(cap, random.uniform(base, previous_delay * 3.0))

Implementasi Python Produksi dengan Circuit Breaker

import asyncio, random, time, aiohttp
from urllib.parse import urlparse

class ResilientAgentCrawler:
    def __init__(self, base_delay=1.0, max_delay=60.0, max_retries=5, threshold=4, cooldown=30.0):
        self.base_delay = base_delay
        self.max_delay = max_delay
        self.max_retries = max_retries
        self.threshold = threshold
        self.cooldown = cooldown
        self.failures = {}
        self.opened_at = {}

    def _is_open(self, domain):
        t = self.opened_at.get(domain)
        if not t: return False
        if time.monotonic() - t > self.cooldown:
            del self.opened_at[domain]
            self.failures[domain] = 0
            return False
        return True

    async def fetch(self, session, url):
        domain = urlparse(url).netloc
        if self._is_open(domain):
            raise RuntimeError(f"Circuit Breaker aktif untuk: {domain}")

        delay = self.base_delay
        for attempt in range(1, self.max_retries + 1):
            try:
                async with session.get(url) as resp:
                    if resp.status == 200:
                        self.failures[domain] = 0
                        return await resp.text()
                    elif resp.status == 429:
                        retry_after = resp.headers.get("Retry-After")
                        wait = float(retry_after) if retry_after else random.uniform(self.base_delay, delay * 3.0)
                        delay = min(self.max_delay, wait)
                        await asyncio.sleep(delay)
                    elif resp.status in (520, 502, 503, 504):
                        self.failures[domain] = self.failures.get(domain, 0) + 1
                        if self.failures[domain] >= self.threshold:
                            self.opened_at[domain] = time.monotonic()
                        delay = min(self.max_delay, random.uniform(self.base_delay, delay * 3.0))
                        await asyncio.sleep(delay)
                    else:
                        resp.raise_for_status()
            except Exception as e:
                if attempt == self.max_retries: raise e
                await asyncio.sleep(delay)

5. Bypass Fingerprint TLS Menggunakan curl_cffi

Di tahun 2026, memanipulasi User-Agent saja sudah usang. Gunakan curl_cffi untuk meniru JA4 fingerprint dan frame HTTP/2 dari browser Chrome:

from curl_cffi.requests import AsyncSession

async def fetch_stealth(url: str):
    async with AsyncSession(impersonate="chrome124") as s:
        res = await s.get(url, timeout=15)
        return res.text

6. Arsitektur Proxy dan Konfigurasi Nginx Server

  • Rotating Residential Proxy: Membagi beban permintaan ke jutaan alamat IP residensial nyata.
  • Mobile Proxy (4G/5G CGNAT): Toleransi tertinggi dari WAF karena alamat IP digunakan bersama oleh ribuan pengguna nyata.
  • Konfigurasi Nginx Pencegah Error 520:
http {
    keepalive_timeout 75s;
    keepalive_requests 10000;
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
}

7. Kesimpulan

Prinsip utama membangun AI crawler tangguh:

  1. Gunakan Decorrelated Jitter untuk mencegah lonjakan retry.
  2. Manfaatkan curl_cffi untuk meniru sidik jari TLS Chrome.
  3. Sinkronkan Keep-Alive server asal menjadi 75 detik.
  4. Pasang Circuit Breaker untuk mengamankan anggaran token LLM.
← Semua artikel
0 / 4