Bun API yang menggunakan middleware cache Redis dapat mengirimkan response lama ketika TTL tidak sinkron dengan event loop. Artikel ini langsung menjelaskan gejala yang terlihat di log dan permintaan, kemudian menguraikan observability yang dibutuhkan untuk menemukan akar masalah TTL, serta langkah perbaikan praktis termasuk tes regresi dan pemantauan pasca-fix.

Gejala dan Indikator Request Menggunakan Cache Kadaluarsa

Ketika middleware Bun mengelola cache Redis, gejala awalnya adalah permintaan yang terus menerima data lama.

Gejala lapangan

  • Request hit lama tanpa cache miss: Middleware melayani data yang seharusnya telah dihapus namun tidak memicu cache miss.
  • Log TTL yang melewati batas: Timestamp TTL di log Bun menunjukkan nilai yang tetap padahal Redis sudah memicu expired.
  • Cache miss berulang di interval tidak terduga: Kadang permintaan berikutnya baru menangkap dengan nilai baru setelah jeda panjang, menandakan ketidaksinkronan waktu.

Gejala ini tidak hanya memperlihatkan data usang, tetapi juga menyebabkan beban karena query backend tetap dijalankan saat cache seharusnya aktif.

Observability untuk Menemukan Akar Masalah

Penelusuran sistem harus fokus pada bagaimana Bun dan Redis berinteraksi, serta bagaimana TTL diterapkan pada cache.

Langkah observability

  • Tracing Bun middleware: Gunakan tracing untuk melihat waktu eksekusi middleware cache, apakah ada penundaan sebelum lookup atau update TTL.
  • Latency Redis dan TTL grafis: Pantau latency respon Redis dan grafik TTL untuk melihat apakah nilai TTL di-set ulang atau melewati waktu sebenarnya.
  • Log event lifecycle: Tambahkan log penanda saat middleware membaca cache, men-set TTL, dan meneruskan response.

Jika tracing menunjukkan bahwa Bun menggunakan cache dengan nilai TTL internal yang tidak cocok dengan TTL pada Redis, kemungkinan besarnya adalah kombinasi antara async Redis client dan middleware yang menangani cache secara bersamaan.

Root Cause: TTL Redis Tidak Sinkron dengan Event Loop Bun

Investigasi menunjukkan bahwa middleware membungkus operasi Redis dengan implementasi async yang tidak mengawasi waktu hidup cache secara ketat.

Root cause utamanya:

  • Async Redis client: Caller menulis data ke Redis dengan TTL, tetapi Bun middleware memutuskan untuk memperbaruinya lagi tanpa menunggu respon, sehingga TTL di Redis tidak diperbarui sesuai urutan operasi event loop.
  • Konfigurasi TTL yang tumpang tindih: Middleware mengisi cache dan langsung mengatur TTL lokal (misalnya di cache memory) tanpa sinkronisasi, sehingga response yang di-cache tetap kadaluarsa di Redis namun middleware menganggap masih valid.

Akibatnya, middleware Bun terus mengirimkan cache lama meski Redis sudah membersihkan entry tersebut karena TTL tidak sama antara kedua lapisan.

Perbaikan dan Validasi

Langkah-langkah berikut membuat TTL sinkron dan mencegah cache usang:

1. Penyesuaian TTL

Pastikan hanya satu titik yang mengatur TTL—misalnya middleware akan mengatur TTL di Redis dan mengandalkan data tersebut sebagai sumber kebenaran.

// Contoh konfigurasi TTL di middleware Bun
const CACHE_TTL = 60; // detik
const cacheKey = `user:${userId}`;
await redis.set(cacheKey, JSON.stringify(payload), { EX: CACHE_TTL });

Hindari logika TTL tambahan di level memory yang bisa membuat nilai divergen.

2. Penambahan Lock

Gunakan mekanisme distributed lock sederhana saat cache di-populate untuk memastikan hanya satu request yang memicu set TTL. Misalnya:

const lockKey = `${cacheKey}:lock`;
if (!(await redis.set(lockKey, '1', { NX: true, EX: 5 }))) {
  return await serveFromCache(cacheKey);
}
try {
  const payload = await fetchSource();
  await redis.set(cacheKey, JSON.stringify(payload), { EX: CACHE_TTL });
} finally {
  await redis.del(lockKey);
}

Hal ini mengurangi race condition antara update cache dan TTL.

3. Upgrade Library dan Regression Test

Pastikan client Redis yang digunakan kompatibel dengan event loop Bun terbaru. Upgrade library apabila terdapat perbaikan pada handling TTL, lalu jalankan regression test yang mensimulasikan beban concurrent agar memastikan cache tidak menghidupkan stale data.

4. Observasi Pasca-fix

Setelah perbaikan, pantau:

  • Grafik cache hit ratio agar tidak menurun drastis.
  • TTL log untuk memastikan waktu hidup konsisten.
  • Latency Redis untuk melihat tidak ada lonjakan karena lock.

Checklist Monitoring Pasca-perbaikan

  • Tracer Bun mencatat durasi middleware cache dan menampilkan status hit/miss.
  • Grafik TTL Redis menunjukkan penyesuaian interval yang konsisten.
  • Alert jika cache miss berulang pada endpoint yang harusnya cached.
  • Log distributed lock mencatat keberhasilan release untuk mencegah deadlock.

Checklist ini membantu memastikan solusi tetap stabil dan memudahkan deteksi regresi.