Deployment bertahap dengan feature flag dan rollback berbasis metrik cocok ketika Anda ingin merilis perubahan perilaku aplikasi tanpa langsung membuka fitur ke semua pengguna. Pendekatan ini memungkinkan kode baru sudah terpasang di production, tetapi aktivasi fitur dikendalikan lewat konfigurasi sehingga rollback bisa dilakukan cepat dengan mematikan flag, tanpa menunggu proses deploy ulang penuh.
Untuk backend dan web app, pola ini sangat berguna saat perubahan menyentuh alur bisnis, query database, integrasi pihak ketiga, atau endpoint yang berisiko menaikkan error rate dan latency. Kuncinya bukan hanya menyalakan flag secara bertahap, tetapi menautkan keputusan lanjut atau rollback ke metrik yang jelas: error rate, latency p95, throughput, dan saturation.
Kapan feature flag lebih tepat daripada blue-green atau canary
Feature flag sering disamakan dengan canary release, padahal fokusnya berbeda. Canary biasanya membagi traffic ke versi deployment yang berbeda di level infrastruktur atau routing. Feature flag membagi perilaku aplikasi di level kode dan konfigurasi. Anda bisa memakai keduanya bersama-sama, tetapi ada situasi di mana feature flag lebih tepat.
Pilih feature flag jika:
- Anda ingin mengaktifkan fitur hanya untuk tenant, akun internal, region, atau segmen pengguna tertentu.
- Anda butuh kill switch cepat tanpa mengganti image/container atau merestart banyak instance.
- Perubahan hanya menyentuh sebagian alur aplikasi, bukan seluruh release artifact.
- Anda ingin melakukan dark launch: kode aktif sebagian di backend, tetapi belum diekspos ke pengguna umum.
- Anda perlu memisahkan deploy kode dari keputusan bisnis kapan fitur dibuka.
Jangan terlalu mengandalkan feature flag jika:
- Perubahan melibatkan migrasi skema database yang tidak kompatibel dua arah.
- Anda perlu menguji versi runtime, image, atau konfigurasi infrastruktur yang benar-benar berbeda.
- Logika flag menjadi terlalu kompleks dan justru meningkatkan risiko bug.
Singkatnya, feature flag lebih tepat untuk kontrol perilaku aplikasi, sedangkan blue-green atau canary lebih cocok untuk kontrol pergantian versi environment atau deployment unit.
Alur rilis yang praktis: dari persiapan hingga eksposur bertahap
1. Persiapkan flag sebelum deploy
Jangan membuat flag hanya sebagai if/else sederhana tanpa desain operasional. Sebelum kode dirilis, tentukan hal-hal berikut:
- Nama flag yang jelas, misalnya
checkout.v2atausearch.new-ranking. - Owner: tim atau orang yang bertanggung jawab.
- Tujuan dan risiko: apa yang berubah dan kegagalan seperti apa yang mungkin muncul.
- Strategi target: internal only, tenant tertentu, persentase traffic, atau kombinasi.
- Metrik sukses dan abort: ambang batas kapan rollout lanjut atau dihentikan.
- Tanggal kedaluwarsa flag: kapan flag harus dihapus agar tidak jadi utang teknis.
Implementasi flag sebaiknya server-side authoritative untuk fitur backend penting. Untuk frontend, evaluasi bisa tetap dilakukan di backend atau melalui konfigurasi yang aman, tergantung kebutuhan. Hal yang penting: keputusan akhir untuk alur sensitif seperti billing, pricing, atau authorization sebaiknya tidak hanya bergantung pada client.
2. Deploy kode dengan flag default off
Pada tahap ini, kode baru sudah masuk production tetapi belum terlihat atau belum aktif untuk user umum. Flag dalam keadaan off menjadi perlindungan awal jika ternyata ada masalah saat startup, integrasi, atau beban awal.
Pastikan jalur lama tetap berfungsi penuh. Jika Anda mengganti query, algoritma, atau provider eksternal, pertahankan fallback ke perilaku lama selama masa rollout.
3. Lakukan dark launch
Dark launch berarti komponen baru mulai berjalan terbatas tanpa mengubah pengalaman pengguna akhir secara penuh. Contohnya:
- Menjalankan query baru di belakang layar untuk membandingkan hasil, tetapi respons user masih memakai hasil lama.
- Mengirim salinan event ke pipeline baru tanpa menjadikannya sumber utama.
- Memproses response dari integrasi baru sebagai observasi, tetapi keputusan bisnis tetap memakai integrasi lama.
Tujuan dark launch adalah menguji kompatibilitas dan profil performa di production dengan risiko minimal. Namun jangan lupa: dark launch tetap bisa menambah beban CPU, memori, koneksi DB, atau queue. Karena itu, metrik infrastruktur tetap harus dipantau walaupun fitur belum tampak ke pengguna.
4. Expose ke tenant tertentu atau persentase traffic kecil
Setelah dark launch stabil, buka fitur ke target yang lebih sempit terlebih dahulu. Ada dua pola umum:
- Per tenant / akun: cocok untuk SaaS B2B karena dampaknya lebih terlokalisasi dan mudah dikomunikasikan.
- Persentase traffic: cocok untuk traffic tinggi yang homogen, asalkan penentuan persentase bersifat stabil.
Untuk persentase traffic, gunakan consistent hashing atau penentuan berbasis identitas stabil seperti user_id atau tenant_id. Hindari random murni per request karena pengguna bisa berpindah-pindah pengalaman dan menyulitkan debugging.
// Contoh pseudo-code evaluasi flag berbasis tenant dan persentase yang stabil
function isFeatureEnabled(context, config) {
if (config.killSwitch === true) return false;
if (config.allowedTenants.includes(context.tenantId)) {
return true;
}
const bucket = stableHash(context.userId || context.tenantId) % 100;
return bucket < config.rolloutPercentage;
}Jika fitur berisiko tinggi, mulai dari tenant internal, akun staging-like, atau pelanggan yang sudah setuju menjadi early adopter. Ini lebih aman daripada langsung membuka 5% user acak yang mungkin menyentuh alur kritis.
5. Naikkan eksposur hanya jika metrik stabil
Jangan menaikkan rollout hanya karena tidak ada laporan manual. Gunakan interval observasi yang cukup untuk melihat dampak nyata pada traffic produksi. Tiap kenaikan persentase harus dianggap sebagai perubahan terkontrol, bukan langkah otomatis tanpa pengawasan.
Contoh tahapan yang umum dipakai secara praktis:
- internal only
- 1 tenant pilot atau 1% traffic
- 5%
- 10%
- 25%
- 50%
- 100%
Tahapan sebenarnya tergantung profil risiko sistem Anda. Untuk endpoint yang sensitif terhadap lonjakan latency atau bottleneck database, langkah kecil lebih aman daripada kenaikan besar.
Metrik wajib dipantau dan cara memakainya untuk abort
Rollback berbasis metrik berarti Anda sudah menentukan sebelum rilis: metrik apa yang dipantau, sumber datanya apa, dan kapan rollout harus dihentikan. Tanpa ini, keputusan rollback sering terlambat atau terlalu subjektif.
1. Error rate
Ini metrik paling langsung untuk mendeteksi regresi fungsional. Pantau error di level yang relevan:
- HTTP 5xx untuk API
- exception rate di service
- failure rate pada job queue
- error dari integrasi eksternal
- domain error penting, misalnya gagal checkout atau gagal membuat invoice
Jangan hanya melihat total error global. Idealnya, pisahkan berdasarkan endpoint, feature flag state, tenant, atau dependency terkait. Jika tidak, regresi lokal bisa tertutup oleh volume traffic lain yang normal.
2. Latency p95
Rata-rata latency sering menipu. Satu perubahan query atau integrasi bisa memperburuk ekor distribusi tanpa terlalu mengubah mean. Karena itu, latency p95 lebih berguna untuk rollout bertahap, terutama pada endpoint dengan traffic tinggi.
Pantau latency end-to-end dan, jika memungkinkan, latency per dependency: database, cache, upstream API, dan queue processing.
3. Throughput
Throughput membantu melihat apakah sistem tetap mampu memproses jumlah request atau event yang sama. Penurunan throughput bisa berarti ada bottleneck, lock contention, retry berlebihan, atau thread/worker yang habis, walaupun error rate belum langsung naik.
4. Saturation
Saturation menunjukkan seberapa dekat resource ke batasnya. Ini penting karena beberapa rollout awal terlihat sehat di 1%, tetapi mulai bermasalah di 25% saat koneksi pool, CPU, memori, atau worker queue mendekati kapasitas maksimum.
Contoh sinyal saturation:
- CPU mendekati penuh secara konsisten
- memori naik dan memicu GC lebih agresif atau OOM
- connection pool database sering habis
- queue depth meningkat terus
- thread pool / worker concurrency mentok
Contoh kondisi abort
Kondisi abort sebaiknya tertulis jelas di runbook. Anda tidak perlu angka absolut yang seragam untuk semua sistem, tetapi prinsipnya harus konkret. Misalnya:
- Error rate fitur baru meningkat signifikan dibanding baseline endpoint yang sama.
- Latency p95 endpoint terdampak naik konsisten selama beberapa interval observasi.
- Queue backlog atau connection pool saturation meningkat setelah flag dinyalakan.
- Muncul kesalahan domain kritis: pembayaran gagal, duplikasi order, data tidak sinkron.
Catatan: bandingkan metrik terhadap baseline yang setara: endpoint yang sama, jam traffic yang mirip, dan jika bisa dipisahkan antara request dengan flag on vs off. Tanpa pembanding yang benar, Anda bisa salah menyalahkan fitur baru padahal masalahnya ada pada dependency eksternal.
Implementasi feature flag yang aman untuk rollback cepat
Pisahkan evaluasi flag dari logika bisnis inti
Jangan sebar evaluasi flag di banyak tempat tanpa kontrol. Bungkus evaluasi dalam komponen khusus agar mudah diaudit dan dimatikan. Contohnya pada service backend:
class CheckoutService {
constructor(flagClient, legacyProcessor, newProcessor) {
this.flagClient = flagClient;
this.legacyProcessor = legacyProcessor;
this.newProcessor = newProcessor;
}
async process(order, context) {
const enabled = await this.flagClient.isEnabled('checkout.v2', {
userId: context.userId,
tenantId: context.tenantId
});
if (!enabled) {
return this.legacyProcessor.process(order, context);
}
return this.newProcessor.process(order, context);
}
}Pola seperti ini membuat rollback cepat karena Anda cukup mematikan checkout.v2, lalu semua request baru kembali ke alur lama.
Sediakan kill switch global
Selain flag granular, siapkan kill switch untuk mematikan fitur dengan prioritas tertinggi. Ini berguna saat provider eksternal bermasalah, beban sistem melonjak, atau ada indikasi korupsi data. Kill switch harus sederhana, terdokumentasi, dan bisa diakses oleh on-call yang berwenang.
Pastikan perubahan state aman saat rollback
Rollback dengan mematikan flag aman hanya jika perubahan yang dilakukan reversible atau setidaknya kompatibel dua arah. Waspadai beberapa jebakan berikut:
- Schema drift: kode baru menulis format data yang tidak dipahami kode lama.
- Side effect eksternal: request ke provider baru sudah menyebabkan tindakan yang tidak bisa dibatalkan.
- Cache key conflict: data dari logika baru dan lama bercampur sehingga hasil menjadi tidak konsisten.
- Background job mismatch: job yang dihasilkan fitur baru tidak dapat diproses worker lama.
Jika ada perubahan data, gunakan pola kompatibilitas bertahap: tambah kolom dulu, dukung pembacaan format lama dan baru, migrasikan perlahan, baru hapus jalur lama setelah stabil.
Checklist pra-rilis untuk deployment bertahap dengan feature flag
- Flag dibuat dengan owner, deskripsi, dan tanggal expiry.
- Default state off di production.
- Kill switch tersedia dan diuji.
- Fallback path ke alur lama masih valid.
- Metrik dan dashboard sudah ada untuk endpoint, dependency, dan resource utama.
- Alert atau ambang abort telah disepakati sebelum rollout.
- Log terstruktur menyertakan status flag, tenant, atau correlation id bila relevan.
- Tracing memadai untuk melihat perbedaan jalur lama vs baru.
- Uji dark launch atau simulasi beban telah dilakukan bila fitur memengaruhi DB/API eksternal.
- Perubahan database sudah dicek kompatibilitas maju-mundur.
- Runbook rollback siap dan diketahui on-call.
- Akses perubahan konfigurasi dibatasi dan diaudit.
Contoh runbook insiden singkat saat rollout gagal
Runbook tidak perlu panjang, tetapi harus bisa dijalankan di bawah tekanan. Contoh struktur praktis:
Trigger
- Error rate endpoint meningkat setelah
checkout.v2dinaikkan dari 5% ke 25%. - Latency p95 dan queue backlog ikut naik.
Langkah respons
- Konfirmasi korelasi waktu antara perubahan rollout dan anomali metrik.
- Periksa apakah anomali hanya terjadi pada request dengan flag on.
- Matikan flag atau turunkan rollout ke 0% menggunakan kill switch/config service.
- Verifikasi request baru kembali ke jalur lama.
- Pantau 2-3 interval observasi untuk memastikan error rate dan latency turun.
- Jika ada job yang sudah telanjur diproduksi oleh jalur baru, hentikan consumer terkait atau aktifkan handler fallback bila tersedia.
- Umumkan status ke channel insiden: waktu rollback, dampak, dan status mitigasi.
Validasi pasca-rollback
- Error rate kembali mendekati baseline.
- Latency p95 turun.
- Queue depth atau saturation membaik.
- Tidak ada tenant tambahan yang masih menerima fitur karena cache konfigurasi stale.
Tips debugging: salah satu masalah umum adalah cache flag yang terlalu lama. Jika rollback dilakukan lewat config service tetapi instance aplikasi masih menyimpan nilai lama, sebagian traffic bisa tetap masuk ke jalur baru. Pastikan TTL cache flag dan mekanisme invalidasinya sesuai kebutuhan operasional.
Contoh postmortem ringan setelah rollback
Postmortem ringan membantu tim belajar tanpa menunggu dokumen besar. Fokus pada fakta teknis dan perbaikan sistemik.
Ringkasan insiden
Pada rollout checkout.v2 dari 5% ke 25%, error rate checkout meningkat dan latency p95 memburuk. Tim melakukan rollback dengan mematikan flag dalam beberapa menit tanpa deploy ulang. Dampak terbatas pada sebagian traffic yang menerima fitur baru.
Akar masalah
Query baru menambah beban pada database karena tidak memanfaatkan indeks yang sesuai untuk pola akses production. Pada 5% traffic gejalanya belum terlihat jelas, tetapi pada 25% connection pool mulai jenuh dan request timeout meningkat.
Apa yang berjalan baik
- Flag default off dan kill switch tersedia.
- Rollback dapat dilakukan cepat tanpa menunggu pipeline deploy.
- Dashboard memisahkan metrik berdasarkan status flag sehingga korelasi cepat terlihat.
Apa yang perlu diperbaiki
- Dark launch belum mengukur dampak query terhadap connection pool secara memadai.
- Abort condition untuk saturation belum cukup eksplisit.
- Tenant pilot belum mewakili pola traffic production yang berat.
Tindakan lanjutan
- Optimalkan query dan tambahkan indeks yang diperlukan setelah validasi akses nyata.
- Tambahkan metrik pool exhaustion dan lock wait ke dashboard rollout.
- Perbarui checklist agar tenant pilot mencakup traffic dengan volume tinggi.
- Tentukan expiry date flag agar jalur lama dan baru tidak hidup terlalu lama bersamaan.
Pencegahan agar feature flag tidak menjadi utang teknis
1. Tetapkan ownership flag
Setiap flag harus punya owner yang bertanggung jawab atas rollout, monitoring, dan penghapusan flag setelah tidak dibutuhkan. Flag tanpa owner sering tertinggal bertahun-tahun dan membuat logika aplikasi sulit dipahami.
2. Gunakan expiry flag
Feature flag untuk rollout seharusnya bersifat sementara. Jika fitur sudah 100% stabil, jadwalkan penghapusan conditional path lama. Semakin lama dua jalur hidup bersamaan, semakin tinggi biaya testing, debugging, dan risiko perilaku tidak konsisten.
3. Audit konfigurasi secara berkala
Lakukan audit terhadap:
- flag yang tidak lagi dipakai di kode
- flag yang aktif permanen tetapi belum dibersihkan
- rule tenant/segment yang sudah usang
- hak akses perubahan konfigurasi
- riwayat siapa yang mengubah rollout dan kapan
Audit penting karena kesalahan rollout sering berasal dari konfigurasi, bukan dari bug kode semata.
4. Batasi kompleksitas rule
Rule kombinasi seperti tenant A + region B + role C + persentase 20% sering terdengar fleksibel, tetapi sulit diprediksi saat insiden. Untuk rollout operasional, prioritaskan rule yang sederhana dan dapat dijelaskan dengan cepat oleh on-call.
5. Pastikan observability memadai
Tanpa log, metrik, dan tracing yang mengandung konteks flag, Anda hanya punya tombol on/off tanpa visibilitas. Minimal, sertakan nama flag dan variannya pada log atau trace yang relevan agar investigasi lebih cepat.
Kesalahan umum yang sering terjadi
- Menganggap flag selalu aman untuk rollback, padahal ada perubahan data yang tidak kompatibel.
- Rollout tanpa baseline, sehingga tim tidak tahu apakah metrik saat ini memang memburuk.
- Hanya memantau error rate dan melupakan latency, throughput, serta saturation.
- Randomisasi per request sehingga pengalaman user tidak konsisten dan analisis metrik kacau.
- Cache konfigurasi terlalu lama sehingga rollback tidak segera efektif.
- Flag tidak pernah dibersihkan dan akhirnya memperumit code path.
Penutup
Deployment bertahap dengan feature flag dan rollback berbasis metrik memberi kontrol yang lebih halus dibanding menunggu deploy ulang ketika rilis bermasalah. Nilai utamanya ada pada pemisahan antara pengiriman kode dan aktivasi fitur, sehingga Anda bisa melakukan dark launch, membuka fitur ke tenant tertentu atau persentase traffic kecil, lalu memutuskan lanjut atau abort berdasarkan sinyal yang objektif.
Agar pendekatan ini benar-benar aman, jangan berhenti di implementasi flag. Siapkan fallback path, kill switch, ownership yang jelas, expiry date, audit konfigurasi, serta metrik yang benar-benar relevan terhadap risiko sistem. Dengan begitu, rollback bukan tindakan panik, tetapi bagian normal dari proses rilis yang terukur.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!