Pengenalan Kasus Debugging Bun API

Kasus ini menjawab masalah Debugging Bun API: Menangani Deadlock Koneksi Redis di Retry ketika permintaan retry membuat endpoint menjadi lambat atau hang. Penyelidikan langsung menunjukkan bahwa permintaan backup memicu banyak retry simultan, mengunci koneksi Redis, lalu event loop Bun terasa tidak responsif.

Jawaban cepatnya: kombinasikan pengaturan batas koneksi Redis, timeout, dan backoff agar retry tidak saling menunggu, lalu pantau metrik event loop serta connection pool sebelum dan sesudah perbaikan.

Gejala dan Observasi

Gejala Nyata

  • API yang awalnya sukses menjadi hang ketika client melakukan retry (misalnya di SDK mobile).
  • Respons timeout server meningkat walau tidak ada peningkatan beban signifikan.
  • Log Bun mencatat retry yang berjalan sepanjang waktu tanpa menyelesaikan kerja.

Observasi Metrik dan Trace

Kami mengamati beberapa indikator utama:

  • Event Loop Block: Bun bun dev --watch atau metrik telemetry memperlihatkan latensi event loop drastis naik ketika retry terjadi.
  • Connection Pool Redis Penuh: Telemetri Redis (misalnya client.INFO atau monitoring Redis Enterprise) menunjukkan jumlah koneksi mencapai maksimal, sementara request masih menunggu.
  • Retry Berulang: Log Bun memperlihatkan retry dipicu berbarengan tanpa backoff, sehingga request baru menunggu koneksi.

Pola ini menunjuk pada deadlock kolektif: semua retry menahan koneksi Redis, pool penuh, event loop menunggu I/O, sehingga API tidak responsif.

Konfigurasi Bun + Redis yang Dikaji

Berikut contoh konfigurasi Bun dengan Redis client yang relevan:

import { createClient } from '@redis/client'

const redis = createClient({
  url: process.env.REDIS_URL,
  socket: {
    connectTimeout: 1_000,
    reconnectStrategy: () => 1_000
  },
  maxRetriesPerRequest: 3,
  name: 'api-bun-retry'
})

redis.on('error', (err) => console.error('Redis error', err))
await redis.connect()

Konfigurasi awal ini tidak mengatur batas pool atau backoff, sehingga Bun hanya meneruskan koneksi yang tersedia sampai habis.

Langkah Rekonstruksi (Reproduce)

  1. Atur BUN_ENV=production (atau sesuai) untuk meniru perilaku deployment.
  2. Jalankan skrip yang mengirim request dengan retry agresif (misalnya 5 kali dengan timeout pendek) ke endpoint Bun yang mengakses Redis.
  3. Perhatikan berulangnya retry di log serta status Redis pool (dari CLIENT LIST).
  4. Gunakan bun test atau load test ringan untuk memastikan simulasi tidak melampaui kapasitas biasa.

Hasilnya: event loop mengalami delay, request baru menunggu koneksi, dan API tampak hang.

Pengamatan dengan Alat Monitoring

Log dan Telegraph

  • Tambahkan log terstruktur untuk mencatat retry serta waktu tunggu koneksi Redis.
  • Gunakan Bun telemetry (misalnya BUN_TELEMETRY=1) untuk melihat latensi event loop.

BUN_ENV dan Telemetri

Set BUN_ENV=production untuk memastikan bundle dan tracing meniru produksi. Pastikan telemetry mencatat metrik seperti event loop delay dan active handles untuk mengidentifikasi blocking.

Analisis dan Perbaikan

Root Cause: Deadlock di Retry

Masalah inti adalah retry serempak mengkonsumsi semua koneksi Redis, sementara masing-masing operasi menunggu penyelesaian. Karena connection pool penuh, request baru tidak bisa mengeksekusi, sehingga Bun mem-block event loop.

Perbaikan Langkah-demi-Langkah

  • Resize Pool Redis atau Batasi Konkurensi: Jika menggunakan pooling eksplisit (misalnya @redis/client dengan connectionLimit), tambahkan limit dan minta permintaan menunggu secara terkontrol.
  • Timeout Lebih Ketat: Tentukan connectTimeout dan commandTimeout sehingga operasi yang terjebak dilepas lebih cepat.
  • Retry dengan Backoff: Terapkan mekanisme exponential backoff dengan jitter agar retry tidak menyatu secara simultan. Contoh pola sederhana:
async function retryRedis(operation, attempt = 0) {
  try {
    return await operation()
  } catch (err) {
    if (attempt >= 3) throw err
    await new Promise(r => setTimeout(r, 50 * 2 ** attempt + Math.random() * 30))
    return retryRedis(operation, attempt + 1)
  }
}

Kombinasi batas koneksi, timeout, dan backoff memastikan request tidak membuat deadlock baru.

Verifikasi dan Pencegahan Regresi

Verifikasi

  • Jalankan benchmark ringan dengan retry sehingga load serupa tercipta.
  • Bandingkan metrik event loop delay dan active handles sebelum dan sesudah patch.
  • Monitor logs Redis apakah masih ada waiting connection.

Pencegahan Regresi

  • Tambahkan test integrasi yang memicu retry butuh waktu, lalu pastikan fallback tidak menutup koneksi.
  • Gunakan monitoring berkelanjutan (telemetry Bun + Redis metrics) untuk mendeteksi pool penuh.
  • Dokumentasikan konfigurasi timeout/backoff sehingga tidak berubah tanpa evaluasi.

Dengan pendekatan ini, Bun API tidak hanya pulih dari deadlock saat retry, tetapi juga siap menghadapi beban retry di masa depan.