Ketika Rollback Justru Memperburuk Keadaan (dan Apa yang Harus Dilakukan)

Kamu baru saja mendeploy versi baru. Pipeline hijau. Health check lolos. CPU dan memory normal. Tapi HP-mu mulai bergetar dengan pesan dari pengguna. Fitur yang kemarin berfungsi sekarang rusak. Data yang ditulis ke database tampak salah. Dan log error? Tidak ada yang aneh.

Inilah momen ketika sebagian besar tim berpikir: "Coba rollback saja." Kedengarannya sederhana. Tukar versi baru dengan versi lama. Masalah selesai. Namun dalam praktiknya, rollback bisa mengubah masalah yang masih terkendali menjadi bencana. Versi lama mungkin tidak memahami data yang sudah ditulis oleh versi baru. Skema database mungkin sudah berubah. Atau rollback itu sendiri memakan waktu lama sehingga lebih banyak pengguna yang terdampak selama transisi.

Rollback bukanlah tombol yang bisa kamu tekan. Ini adalah keputusan yang kamu buat di bawah tekanan, dengan informasi yang tidak lengkap, dan dengan konsekuensi yang menjalar ke seluruh sistem. Memahami kapan dan bagaimana melakukan rollback -- dan kapan tidak -- adalah yang membedakan tim yang pulih dengan cepat dari tim yang justru memperburuk keadaan.

Sinyal Nyata untuk Rollback

Kebanyakan tim mengandalkan health check untuk memutuskan apakah sebuah deployment sehat. Tapi health check hanya memberi tahu apakah aplikasi berjalan secara teknis. Mereka tidak memberi tahu apakah aplikasi melakukan hal yang benar.

Pertimbangkan skenario ini: versi barumu berhasil menulis pesanan pelanggan ke database. Tidak ada error. Tidak ada crash. Tapi data pesanan disimpan dengan format mata uang yang salah. Aplikasi secara teknis sehat, tapi secara fungsional rusak. Health check tidak akan menangkap ini. Monitoringmu mungkin juga tidak akan menangkapnya, kecuali kamu memiliki metrik khusus tingkat bisnis.

Keputusan untuk rollback biasanya datang dari kombinasi sinyal:

  • Health check yang mulai gagal
  • Tingkat error yang melonjak
  • Laporan pengguna yang menggambarkan perilaku yang tidak sesuai ekspektasi
  • Metrik bisnis yang menyimpang dari pola normal

Tapi ada faktor lain yang sering diabaikan tim: waktu. Berapa lama kamu menunggu sebelum memutuskan rollback? Lima menit? Tiga puluh menit? Sampai ada yang complain? Semakin lama kamu menunggu, semakin banyak data yang ditulis oleh versi baru. Dan semakin banyak data yang ditulis, semakin sulit rollback-nya.

Tetapkan jendela observasi yang jelas sebelum setiap deployment. Putuskan sebelumnya: jika kami tidak melihat masalah dalam 15 menit pertama, kami anggap stabil. Jika kami melihat masalah dalam jendela itu, kami rollback segera. Ini menghilangkan keraguan yang membuat situasi buruk menjadi lebih buruk.

Mengapa Stateless dan Stateful Tidak Sama

Kemudahan rollback hampir sepenuhnya tergantung pada apakah aplikasimu menyimpan state.

Untuk aplikasi stateless, rollback itu mudah. Kamu mengarahkan lalu lintas kembali ke versi lama. Tidak ada data yang perlu dipulihkan. Tidak ada skema yang perlu diselaraskan. Versi lama melanjutkan dari tempat terakhirnya karena tidak pernah bergantung pada state dari versi baru. Inilah mengapa layanan stateless sering menjadi kandidat pertama untuk strategi rollback agresif.

Untuk aplikasi stateful, rollback adalah permainan yang berbeda. Bayangkan versi barumu menulis 10.000 record ke database dengan field baru yang tidak diketahui oleh versi lama. Ketika kamu rollback aplikasi, versi lama mencoba membaca record tersebut. Aplikasi crash karena format data tidak sesuai dengan yang diharapkan. Atau lebih buruk lagi, versi baru mengubah struktur tabel database. Sekarang aplikasi lama bahkan tidak bisa mulai karena skema tidak kompatibel.

Inilah jebakannya: rollback aplikasi tanpa rollback data. Jika deployment-mu mengubah skema database atau menulis data dalam format baru, rollback kode saja tidak cukup. Kamu perlu salah satu dari:

  • Mengembalikan database ke titik sebelum deployment
  • Menulis skrip migrasi yang membalikkan perubahan skema
  • Menerima bahwa beberapa data akan hilang atau rusak

Masing-masing opsi ini memiliki biaya dan risiko sendiri. Restore database memakan waktu dan mungkin kehilangan data sah yang ditulis oleh bagian lain sistem selama jendela tersebut. Migrasi balik perlu diuji dan siap sebelum deployment, bukan ditulis di bawah tekanan.

Tiga Strategi yang Benar-Benar Berhasil

Situasi yang berbeda membutuhkan pendekatan rollback yang berbeda. Berikut tiga strategi yang digunakan tim dalam praktik.

Diagram keputusan berikut dapat memandu pilihanmu:

flowchart TD A[Failure detected] --> B{Stateful?} B -->|No| C[Rollback or traffic shift] B -->|Yes| D{Data schema changed?} D -->|Yes| E{Can fix forward quickly?} E -->|Yes| F[Forward fix] E -->|No| G[Accept and patch] D -->|No| H{Logic bug or perf issue?} H -->|Logic bug| I{Can fix forward quickly?} I -->|Yes| J[Forward fix] I -->|No| K[Traffic shift or rollback] H -->|Perf issue| L[Traffic shift or rollback]

Forward Fix

Alih-alih kembali ke versi lama, kamu membangun dan mendeploy versi baru yang memperbaiki masalah. Ini sering menjadi opsi teraman untuk aplikasi stateful karena kamu tidak perlu membatalkan perubahan data. Kamu hanya perlu memperbaikinya.

Forward fix bekerja dengan baik ketika:

  • Bug terisolasi dan bisa diperbaiki dengan cepat
  • Pipeline-mu bisa mengirimkan versi baru dalam hitungan menit
  • Data yang ditulis oleh versi yang rusak masih bisa dipulihkan atau dimigrasi

Risikonya adalah waktu. Jika bug parah dan perbaikannya memakan waktu berjam-jam, pengguna terus mengalami masalah selama kamu bekerja. Forward fix membutuhkan keyakinan pada kemampuan tim untuk mendiagnosis dan memperbaiki masalah dengan cepat.

Traffic Shift

Jika kamu menggunakan deployment canary atau blue-green, rollback semudah mengarahkan lalu lintas kembali ke versi lama. Versi lama masih berjalan dan siap menerima lalu lintas. Tidak ada proses deployment yang harus ditunggu. Tidak ada periode transisi di mana beberapa pengguna mengenai versi lama dan yang lain mengenai versi baru.

Ini adalah metode rollback tercepat. Tapi ini hanya berfungsi jika kamu mendesain strategi deployment dengan ini dalam pikiran. Jika kamu menggunakan rolling update, kamu tidak memiliki versi lama yang siaga. Rollback berarti menjalankan seluruh proses deployment lagi dengan artefak lama. Itu memakan waktu dan membuat pengguna terpapar error selama transisi.

Berikut contoh konkret menggunakan Kubernetes untuk mengalihkan lalu lintas kembali ke versi lama selama deployment canary:

# Periksa pembagian lalu lintas saat ini (asumsikan service dengan dua selector)
kubectl get virtualservice my-app -o jsonpath='{.spec.http[0].route[*].weight}'

# Alihkan 100% lalu lintas ke versi lama (v1)
kubectl patch virtualservice my-app --type='json' -p='[
  {"op": "replace", "path": "/spec/http/0/route/0/weight", "value": 100},
  {"op": "replace", "path": "/spec/http/0/route/1/weight", "value": 0}
]'

# Verifikasi perubahan
kubectl get virtualservice my-app -o yaml | grep -A5 "route:"

Pendekatan ini mengasumsikan kamu memiliki service mesh atau ingress controller (seperti Istio atau Traefik) yang mendukung weighted routing. Untuk pengaturan yang lebih sederhana, kamu bisa mencapai hal yang sama dengan memperbarui service selector untuk menunjuk secara eksklusif ke pod versi lama.

Accept and Patch

Terkadang keputusan terbaik adalah membiarkan versi baru berjalan dan memperbaiki masalah di tempat. Ini terdengar kontraintuitif, tapi pertimbangkan: jika versi baru sudah menulis data yang tidak bisa dibaca versi lama, rollback menjamin downtime. Membiarkan versi baru berjalan berarti pengguna masih bisa menggunakan sistem sementara kamu mengerjakan perbaikan.

Pendekatan ini berfungsi ketika:

  • Masalahnya tidak kritis (masalah tampilan minor, bug yang tidak memblokir)
  • Data yang ditulis oleh versi baru berharga dan akan hilang jika rollback
  • Tim bisa mengirimkan patch dalam waktu yang wajar

Kuncinya adalah mengetahui kapan harus menerima dan kapan harus bertindak. Jika masalah mempengaruhi fungsionalitas inti atau merusak data, accept and patch bukanlah pilihan yang tepat.

Checklist Praktis Sebelum Deployment Berikutnya

Sebelum kamu mendeploy, bahas pertanyaan-pertanyaan ini dengan tim:

  • Sinyal apa yang akan memicu keputusan rollback? (health, error, laporan pengguna, metrik bisnis)
  • Berapa lama kita akan mengamati sebelum memutuskan? (5 menit, 15 menit, 30 menit)
  • Apakah deployment ini mengubah skema database atau format data?
  • Jika ya, apakah kita memiliki rencana migrasi balik atau restore yang sudah diuji?
  • Apakah versi lama masih berjalan dan siap menerima lalu lintas?
  • Bisakah kita memperbaiki maju (forward fix) lebih cepat daripada rollback?

Tulis jawabannya. Bagikan dengan tim. Waktu untuk merencanakan rollback adalah sebelum deployment, bukan saat insiden.

Intisari

Rollback bukanlah jaring pengaman universal. Untuk aplikasi stateless, ini adalah pintu keluar yang andal. Untuk aplikasi stateful, ini bisa menjadi jebakan yang memperburuk keadaan. Keputusan untuk rollback tergantung pada seberapa banyak data yang telah terpengaruh, seberapa cepat kamu bisa memperbaiki maju, dan apakah versi lama masih bisa bekerja dengan state sistem saat ini.

Rencanakan jalur rollback-mu sebelum setiap deployment. Kenali sinyalmu. Tetapkan jendela observasi. Dan ingat: terkadang pemulihan terbaik bukanlah mundur, tetapi memperbaiki maju.