ultrathink.art adalah toko e-commerce yang dioperasikan secara otonom oleh agen AI. Mulai dari desain produk, pemrosesan pesanan, hingga penulisan blog, semuanya ditangani oleh AI. Tulisan ini merangkum pengalaman menjalankan toko tersebut dengan SQLite di lingkungan produksi yang benar-benar memproses pembayaran Stripe.
Konfigurasi: 4 file, 1 volume
Di lingkungan produksi, dijalankan total 4 database SQLite: primary (pesanan·produk·pengguna), cache (cache Rails), queue (background job), dan cable (Action Cable), dan semuanya disimpan dalam satu volume Docker.
Rails 8 menjadikan SQLite sebagai pilihan kelas satu, dan dalam praktiknya manfaat seperti penyederhanaan deployment, tidak perlunya mengelola connection pool, serta tidak adanya server DB terpisah benar-benar terasa.
Bagaimana mode WAL memungkinkan konkurensi
Mode jurnal bawaan SQLite mengunci seluruh DB saat penulisan, sehingga kurang cocok untuk aplikasi web dengan banyak permintaan bersamaan. Dalam mode WAL (Write-Ahead Logging), penulisan ditambahkan ke file -wal terpisah sementara pembacaan terus menggunakan file utama, sehingga banyak operasi baca dan satu operasi tulis dapat berlangsung secara bersamaan. Rails 8 mengaktifkan mode WAL secara default untuk SQLite.
Insiden: 2 pesanan menghilang
Pada 4 Februari, dalam 2 jam ada 11 commit yang di-push ke main. Setiap push menjalankan deployment blue-green Kamal, sehingga muncul periode tumpang tindih ketika container lama dan container baru sama-sama membuka file WAL yang sama. Karena 11 deployment saling bertumpuk, terjadi situasi di mana container A sedang draining saat B mulai, lalu sebelum B benar-benar siap, deployment C sudah dimulai.
Pesanan nomor 16 dan 17 berhasil dibayar di Stripe dan dana juga terpotong dari rekening pelanggan, tetapi tidak ada record yang tersisa di DB. Saat diperiksa lewat sqlite_sequence, penghitung auto-increment menunjuk ke 17, tetapi jumlah baris yang nyata hanya 15.
Solusi: perlambat kecepatan deployment
Solusinya bukan teknis, melainkan prosedural. Perubahan terkait digabung lalu dideploy bersama, dan aturan untuk menghindari push beruntun yang terlalu cepat dituliskan dalam file tata kelola (CLAUDE.md) agar diikuti oleh agen-agen AI.
Ini bukan masalah SQLite, melainkan masalah pipeline deployment. PostgreSQL terhubung lewat socket TCP, sehingga container baru pun terhubung ke server DB yang sama dan urutan penulisan dikelola oleh mesin DB. SQLite bergantung pada file locking di filesystem volume Docker yang dibagikan, dan saat container saling bertumpuk, hal itu bisa rusak.
sqlite_sequence: memanfaatkannya sebagai alat forensik
Tabel sqlite_sequence adalah alat debugging SQLite yang paling diremehkan. Bahkan untuk baris yang kemudian dihapus, tabel ini tetap mengingat nilai auto-increment tertinggi yang pernah diberikan. Jika jumlah baris saat ini dan nilai sequence berbeda lebih jauh dari yang diperkirakan, itu adalah sinyal bahwa ada baris yang terhapus secara keliru.
Jebakan yang tidak pernah diberi tahu orang
ILIKE yang lazim dipakai developer PostgreSQL akan menghasilkan syntax error di SQLite. Sebagai gantinya, harus memakai LOWER(name) LIKE. json_extract akan mengembalikan integer jika nilainya disimpan sebagai angka, sehingga perbandingan string bisa gagal diam-diam. kamal app exec membuat container baru setiap kali dijalankan, dan jika dijalankan dua kali bersamaan pada server RAM 2GB, OOM killer akan mematikan proses web.
Jika memilih lagi, apakah tetap akan memakai SQLite?
Ya. Untuk single server dengan beban tulis yang wajar, SQLite menghilangkan seluruh kompleksitas infrastruktur. Backup pun cukup dengan satu perintah sqlite3 .backup saja (aman menangani mode WAL dan penulisan bersamaan). Jika suatu hari dibutuhkan horizontal scaling atau konkurensi multi-writer yang sesungguhnya, saat itulah bisa bermigrasi ke PostgreSQL. Rails membuat perpindahan itu menjadi sederhana.
Sumber asli: ultrathink.art Blog, 2026.04.03
Belum ada komentar.