Footer Berubah, JSON-LD Tidak: Jebakan Boot Cache Settings API
Menulis baris settings langsung ke database tidak mengubah respons API yang menyimpan snapshot saat boot. Urutan debug tiga lapis dan aturan restart.
Ringkasan
Update settings langsung lewat SQL memang masuk di database, tapi endpoint masih balikin nilai lama soalnya API cuma baca snapshot in-memory yang dibuat pas boot. Nulis SQL itu nggak lewat jalur yang bisa refresh snapshot, makanya datanya kelihatan aman tapi nggak pernah kepakai. Solusinya gampang: habis nulis langsung ke DB, tinggal restart API-nya.
Saya menambah satu baris tabel settings langsung lewat SQL. Dari sisi database semuanya terlihat normal: barisnya ada, nilainya benar, kolom updated_at ikut berubah. Lalu saya buka endpoint settings, dan nilainya masih yang lama. Saya muat ulang hasil render server, dan halaman itu terbelah: footer sudah menampilkan nilai baru, blok JSON-LD di head masih berisi nilai sebelumnya.
Salah tebak: bukan lapisan database
Tebakan pertama saya mengarah ke database. Saya curiga salah environment, salah tabel, atau proses API yang terhubung ke instance berbeda. Semua diperiksa, semuanya bersih. Baris yang saya tulis memang ada di database yang sama dengan yang dipakai aplikasi.
Kalau ketiga lapis itu sudah bersih dan nilai tetap tidak berubah, kesimpulannya bukan "data belum masuk". Data sudah masuk, tetapi yang dilayani API bukan data itu. Ada lapis keempat yang tidak terlihat dari sisi database.
Snapshot saat boot dan fallback yang diam
Endpoint settings membaca dari snapshot in-memory yang dibangun sekali saat proses boot. Ketika key tidak ditemukan di snapshot, API mengembalikan nilai default tanpa pesan error apa pun. Tulisan langsung lewat SQL tidak pernah melewati jalur yang memperbarui snapshot itu. Nilai baru ada di database, tidak pernah masuk ke snapshot.
Ini bukan bug. Memang begitu kontraknya.
Setiap cache punya kontrak invalidasi, dan kontrak itulah yang menentukan tulisan mana yang sah. Dokumentasi HTTP caching menjelaskan prinsip yang sama: respons yang tersimpan akan dipakai ulang sampai dianggap stale, dan "proper operation of the cache is critical to the health of the system" [1]. Framework aplikasi meniru model ini. Django mendefinisikan cache sebagai penyimpanan hasil perhitungan mahal agar tidak dihitung ulang, dengan Memcached yang menyimpan semua data langsung di memori [4]. Spring membuat invalidasinya eksplisit: @Cacheable mengisi cache, @CacheEvict menghapus isinya [3]. Tidak ada dari mereka yang menebak perubahan yang datang lewat jalur belakang.
Sisi client menambah satu lapis kebingungan. Pada React, nilai useState untuk kondisi awal "is ignored after the initial render", sehingga komponen client bisa mempertahankan nilai default tetap ketika data fetch kosong atau stale [2]. Itu sebabnya footer dan JSON-LD bisa berbeda: satu lapis membaca nilai segar, lapis lain bertahan pada default yang dihitung saat render pertama.
Urutan debug dari database ke halaman
Urutan pemeriksaan yang akhirnya saya pakai selalu sama: database, lalu endpoint API, lalu halaman yang dirender. Yang menjadi diagnosis adalah ketidakcocokan antar lapis, bukan nilai di satu lapis.
# 1. pastikan baris settings benar-benar sudah tertulis
psql "$DATABASE_URL" \
-c "select key, value, updated_at from app_settings where key = 'site_name';"
# 2. bandingkan dengan yang dilayani API
curl -s https://example.com/api/settings | python3 -m json.tool
Kalau langkah 1 menunjukkan nilai baru dan langkah 2 masih menampilkan nilai lama, masalahnya ada di antara keduanya, bukan di database. Kalau langkah 2 sudah benar tetapi halaman masih salah, masalahnya ada di lapis render atau di fallback default di sisi client.
# 3. restart proses API, lalu ulangi langkah 2
curl -s https://example.com/api/settings | python3 -m json.tool
Setelah restart, nilai baru muncul di JSON. Perubahan setelah restart, tanpa satu pun perubahan data, adalah konfirmasi bahwa cache saat boot yang menyimpan nilai lama.
Pola kontrak seperti ini jarang datang sendirian. Process manager yang membaca berkas environment sekali saat start, konfigurasi yang di-render saat build, HTML yang tertahan di cache edge, semuanya punya watak yang sama: ada satu titik waktu yang menentukan berapa lama nilai lama tetap dilayani. Begitu paham titik itu, gejala serupa di sistem lain tidak lagi menggantung di tebakan.
Aturan operasionalnya jadi sederhana. Setiap kali menulis settings langsung ke database, restart API-nya. Setiap kali meragukan hasil render, curl endpoint-nya dulu sebelum menelusuri kode template. Verifikasi dari lapis paling bawah ke atas, dan jangan pernah menyimpulkan dari satu lapis saja.
Sumber
- HTTP Caching, MDN Web Docs (diakses 2026-11-06)
- useState, React documentation (diakses 2026-11-06)
- Cache Abstraction annotations, Spring Framework documentation (diakses 2026-11-06)
- Django's cache framework, Django documentation (diakses 2026-11-06)