Solusi langsung untuk API produk yang menampilkan data usang

API produk yang seharusnya selalu mengirimkan harga dan stok terkini tetapi terus menayangkan nilai lama biasanya disebabkan oleh cache query yang tidak di-refresh atau race condition saat update. Dalam kasus CodeIgniter 4, penyebab utama adalah cache query layer yang mempertahankan hasil lama karena tidak ada invalidasi saat data berubah. Artikel ini menjelaskan alur debugging: dari pemeriksaan log dan profiler hingga analisis cache layer dan langkah perbaikan yang praktis.

Path debug cepat: identifikasi gejala pada response API, cek apakah cache query aktif, validasi log database, lalu telusuri cache store. Fokus kita adalah memastikan API tidak mengirim data usang meskipun ada update produk baru.

Gejala dan pemeriksaan awal

Deteksi gejala melalui response API dan log

Gejala umum: response API JSON menampilkan harga/stok lama, sementara database sudah berubah. Langkah awal adalah mencocokkan timestamp terakhir di response dengan timestamp update di tabel produk.

Pemeriksaan log CodeIgniter (app/Logs) membantu melihat apakah query SELECT dilakukan saat request masuk. Jika query tidak tereksekusi—misalnya hanya cache hit—log akan menunjukkan tidak ada aktivitas database terkait. Tambahkan profil logging sementara:

$db = \\Config\\Database::connect();
log_message('debug', 'Menarik data produk terbaru');

Jika log tidak muncul selama request API, berarti sistem tidak mencapai layer query.

Profiling query untuk memastikan cache hit

Aktifkan profiler query untuk endpoint API tersebut. Di CodeIgniter 4, Anda bisa memanggil:

return $this->response->setJSON($model->findAll())->setStatusCode(200)->setHeader('Content-Type', 'application/json');

Dengan profiler aktif (Config\\Boot\\COMMON), Anda melihat apakah query dieksekusi atau hanya cache hit. Cari indikator seperti Cache Hit atau query dengan durasi 0ms. Jika query tidak jalan, kemungkinan data dibaca dari cache query.

Analisis cache layer dan root cause

Memahami mekanisme cache query CodeIgniter

Cache query di CI4 menyimpan hasil query dalam storage (file, Redis, dsb.) berdasarkan hash query. Jika cache tidak diinvalidasi setelah update, API terus menyajikan data lama. Periksa konfigurasi cache (app/Config/Cache.php) dan identifikasi storage yang digunakan (misalnya cache()->save()/get()).

Studi kasus: Cache query tidak ter-refresh setelah update stok

Kasus yang ditemui: API mengandalkan model berikut:

public function getProducts()
{
    $cacheKey = 'products_list';
    $cached = cache()->get($cacheKey);
    if ($cached) {
        return $cached;
    }

    $products = $this->select('id,name,price,stock')->findAll();
    cache()->save($cacheKey, $products, 300);
    return $products;
}

Masalahnya muncul bila ada proses update stok di controller lain tanpa invalidasi cache. API tetap mengembalikan $cached. Logs menunjukkan cache hits terus-menerus meskipun ada update di DB.

Root cause: cache diisi sekali dan tidak dihapus saat data berubah, mengakibatkan cache stale. Penyebab tambahan: race condition update + read bersamaan membuat cache tidak pernah di-refresh.

Langkah perbaikan praktis

Invalidasi cache setelah update atau delete

Setiap operasi yang mengubah data produk harus menghapus cache itu. Terapkan pattern:

public function updateProduct(int $id, array $data)
{
    $this->update($id, $data);
    cache()->delete('products_list');
}

Jika menggunakan event model, Anda bisa mendaftarkan listener pada event 'afterUpdate' untuk otomatis menghapus cache. Menyederhanakan prosedur invalidasi membantu memastikan API mengambil data segar.

Tuning query dan cache expiry

Selain invalidasi manual, pertimbangkan menyesuaikan durasi cache agar lebih pendek sesuai frekuensi update. Misalnya, set cache selama 60 detik jika stok berubah tiap menit. Tuning ini membantu sementara sebelum scaling invalidasi otomatis tersedia.

Jangan lupa optimasi query: pastikan index digunakan (misalnya pada kolom id atau category_id) agar fetch cepat tanpa ketergantungan penuh pada cache.

Menangani race condition cache

Race condition terjadi bila dua request update dan read berjalan bersamaan: update selesai sebelum cache dihapus, sehingga read masih mendapatkan nilai lama. Terapkan locking sederhana:

$lockKey = 'products_list_lock';
if (!cache()->get($lockKey)) {
    cache()->save($lockKey, true, 5);
    cache()->delete('products_list');
    cache()->delete($lockKey);
}

Lock menggunakan cache temporary menghindari dua proses saling menimpa. Pastikan lock timeout pendek agar tidak menghambat throughput.

Preventif observability untuk mencegah regresi

Memantau cache hit rate dan TTL

Buat metrik simple: hit rate cache per endpoint API. Log event ketika cache miss menyiratkan query dieksekusi, dan cache hit berarti data disajikan dari cache. Gunakan tools observability (Prometheus, New Relic, dsb.) untuk memantau hit/miss ratio; penurunan hit rate bisa menandakan invalidasi tidak terpanggil.

Alert jika respons API lama atau mismatch data

Setup monitoring synthetic tests yang membandingkan response API dengan data sumber (misalnya query langsung ke DB). Jika perbedaan terdeteksi, kirim alert ke tim backend dan otomatis invalidasi cache.

Best practice: dokumentasi cache dan kontrak update

Dokumentasikan cache keys yang digunakan beserta penghubungnya ke operasi update, agar developer lain tahu kapan harus menghapus cache. Sertakan checklist deployment yang memastikan invalidasi cache dijalankan setiap perubahan schema atau logika update.

Kesimpulan

Debugging cache stale pada API produk CodeIgniter 4 menuntut pemeriksaan log, profil query, dan pemahaman cache layer secara menyeluruh. Invalidasi cache tepat waktu, tuning cache expiry, serta mekanisme locking menangani race condition. Observability lengkap (metrik hit/miss, test data konsistensi) mencegah regresi di masa mendatang. Dengan pendekatan ini, API produk tetap menyajikan data terkini tanpa mengorbankan performa.