Skip to content

Arah DB Dibalik, Semua Asumsi Safety Ikut Terbalik

Adityo Guni Waluyo

Membalik arah db-push jadi db-pull bukan cuma menukar panah: backup lokal dulu, dump divalidasi sebelum dipercaya, aturan backtick berubah di SSH.

Ringkasan

Bikin script db-pull tuh ngeri karena yang ketimpa database lokal, bukan staging lagi. Makanya urutannya dibalik, wajib backup lokal dulu, terus dump staging dicek ukuran sama tanda Dump completed baru di-replace. Terus verifikasinya ketat banget, hitung baris tiap tabel harus sama persis, backtick juga diakalin biar aman di SSH.

deploy/db-pull.sh punya satu baris yang bikin saya berhenti ngetik sebentar: perintah penghapus database yang targetnya laptop saya sendiri. Punya db-push.sh yang nge-replace database staging rasanya biasa aja; staging memang bisa dibangun ulang kapan saja. Begitu bikin kebalikannya, posisi tukar. Staging jadi sumber, dan yang di-replace total itu lokal, lengkap dengan eksperimen setengah jadi yang belum ke-push ke mana-mana.

Insting pertama saya waktu itu sederhana: tinggal salin script lama, balik arah panahnya, beres. Tengok lagi, nggak segitu. Semua pengaman di script lama berdiri di atas satu asumsi, yaitu yang hancur itu staging. Asumsinya kebalik, urutan pengamannya harus ikut kebalik.

Gerbang satu: backup lokal, bukan staging

Di arah pull, hal pertama yang jalan justru backup database lokal ke backup/mude-local-before-pull-*.sql.gz. File inilah tombol revert. Import bermasalah di tengah jalan? Restore file ini, lokal balik seperti semula. Yang lama dipangkas, cuma tiga backup terbaru yang disimpan. Aturannya nggak ada negosiasi: backup ini wajib selesai sebelum satu byte pun diubah.

Gerbang dua: dump dibongkar sebelum dipercaya

Dump staging dijalanin di VPS pakai --single-transaction. Manual MySQL jelasin flag ini mengubah isolation ke REPEATABLE READ dan membuka transaksi sebelum dump dimulai, jadi yang diambil adalah kondisi konsisten di satu titik waktu tanpa memblokir aplikasi yang lagi jalan [1]. Catatan pentingnya: ini cuma berguna untuk tabel transaksional kayak InnoDB.

Hasil dump itu sendiri adalah logical backup: kumpulan statement buat membangun ulang database, bukan copy file fisiknya [5]. Karena sifatnya gitu, dia nggak langsung dipercaya. Tiga pemeriksaan wajib lolos dulu di skrip: ukuran file nggak boleh di bawah ambang, jumlah CREATE TABLE nggak boleh nol, dan lima baris terakhir file wajib mengandung komentar Dump completed, penanda bawaan mysqldump untuk dump yang selesai utuh [1]. Baru setelah itu skrip nekat ke langkah yang manual MySQL sendiri dengan tegas nulis Be very careful with this statement! [2] Jelas kenapa langkah ini ditaruh kelima, bukan pertama.

# gerbang sanity: gagal cepat, sebelum database lokal disentuh
if [ "$dump_bytes" -lt 1000 ] || [ "$table_count" -eq 0 ]; then
  echo "staging dump looks wrong: replace aborted"
  exit 1
fi
gunzip -c "$STAG_DUMP_FILE" | tail -5 | grep -q 'Dump completed' || exit 1

Gerbang tiga: backtick aman di lokal, mati di SSH

Bagian yang paling banyak ngajarin saya justru di ujung skrip: verifikasi. Saya mau bandingkan COUNT(*) per tabel, lokal lawan staging. Query staging harus dieksekusi di VPS lewat SSH, dan persis di situ backtick pembungkus nama tabel jadi ranjau. Shell remote mem-parse string yang dikirim dan memakan backtick sebagai command substitution, jadi SQL yang sampai di server sudah bukan SQL yang saya tulis.

Manual bash mencatat bentuk backquote lama punya aturan yang presisi: backslash kehilangan makna khusus kecuali di depan $, backtick, atau backslash, dan backtick pertama yang nggak di-escape langsung menutup substitusinya [3]. Bentuk $( ... ) yang modern jelas lebih gampang diprediksi. Dua-duanya tetap dievaluasi shell. Strategi saya di SQL remote jadi lain: hilangkan kebutuhan escapingnya sekalian, nama tabel divalidasi dulu, cuma boleh huruf, angka, dan underscore. Tanpa karakter spesial, nggak ada yang perlu di-escape.

Ada ironi kecilnya: backtick untuk nama database di sisi lokal tetap saya pakai. Perintah itu jalan via docker exec langsung di container database [4], nggak pernah lewat SSH. Karakter yang sama, dua konteks beda, nasibnya beda total.

Verifikasi yang sengaja keras

Setelah import selesai, skrip menghitung ulang jumlah baris per tabel. Semua count staging diambil dalam satu koneksi SSH, urutannya dikunci mengikuti urutan tabel lokal, lalu dibandingkan satu per satu. Satu saja angka yang beda, skrip keluar dengan status gagal beserta daftar tabelnya. Nggak ada mode best-effort.

Perubahan terbesar dari script ini sebenarnya bukan fiturnya, tapi urutannya: backup, dump, sanity, replace, verify. Tiap gerbang boleh gagal duluan sebelum langkah yang merusak keburu jalan. Makin lama makin yakin, script yang berani gagal keras di tengah jauh lebih murah daripada script yang sukses setengah dan meninggalkan lokal dalam kondisi setengah staging.

Sumber

Artikel terkait