karawaci.kode

2026-07-03 · 6 min

Postmortem Deploy Jumat Malam Part 2: 12 Bulan Setelah

Satu tahun lalu, saya tulis postmortem deploy hari Jumat — refactor cursor pagination yang break 7 user dalam 30 menit. Saya berjanji: tidak deploy Jumat sore lagi untuk project yang ada paying customer.

12 bulan kemudian, ini follow-up. Apa yang berubah, apa yang tetap, dan satu kali saya deploy Jumat lagi (sengaja, dengan safety net berlapis).

Apa yang berubah di pipeline

1. Automated canary rollout

Sebelumnya: push ke main → semua user dapat versi baru dalam 2 menit.

Sekarang:

  • Push ke main → deploy ke 5% user (via Cloudflare Workers traffic split).
  • 10 menit observasi: error rate, p95 latency, ada deviasi > threshold?
  • Auto-promote ke 25% kalau OK.
  • 10 menit observasi.
  • Auto-promote ke 100%.
  • Total rollout: ~22 menit untuk reach 100%.

Implementation dengan Cloudflare Workers + KV:

// edge router
export default {
  async fetch(req: Request, env: Env) {
    const userId = await getUserIdFromCookie(req);
    const hash = hashUserId(userId) % 100;
    
    const rolloutPct = parseInt(await env.KV.get('rollout-pct') ?? '0');
    
    if (hash < rolloutPct) {
      return fetch('https://api-canary.kami.id' + new URL(req.url).pathname, req);
    }
    return fetch('https://api-stable.kami.id' + new URL(req.url).pathname, req);
  }
};

KV rollout-pct di-update oleh deploy pipeline. Stickiness via userId hash, jadi user yang sudah di canary tetap di canary.

2. Auto-rollback berbasis SLO

Selama canary observation, kalau:

  • Error rate (5xx) di canary > 1% sustained 2 menit, atau
  • P95 latency canary > 1.5x stable, atau
  • Apdex score < 0.85

Trigger automatic rollback: set rollout-pct = 0, alert ke Slack #ops.

Saya pakai Prometheus + Alertmanager (lihat setup di Prometheus Grafana SaaS Jakarta) untuk trigger ini via webhook.

Webhook ke deploy controller:

curl -X POST https://deploy.kami.id/rollback \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"reason":"error_rate_threshold","metric":"0.024","deploy_id":"..."}'

Sejak deploy auto-rollback ini live: 4 rollback dalam 12 bulan, semua < 90 detik dari trigger ke 0% rollout.

3. Staging dataset yang representatif

Postmortem sebelumnya, bug saya tidak detect karena staging cuma 200 record. Sekarang:

  • Cron Sunday 02:00: dump production data, anonymize PII, restore ke staging.
  • Anonymize via custom script: nama → faker, email → hash, NIK/KTP → random valid format, alamat → faker (kota tetap asli untuk geo query test).
  • Volume staging matchproduction: 50k+ invoice, edge case representatif.

Hasil: 2 bug yang akan masuk production tertangkap di staging dalam 12 bulan. Bug terbesar: query timeout di tabel audit_log saat dataset > 10M row (production sudah ke sana, staging dulu tidak).

Yang tetap

1. Tidak deploy Jumat sore

Aturan tetap. Tapi konteksnya berubah: sekarang ada tim 4 engineer (dulu saya sendiri). Aturan ditulis di runbook:

Deploy production HANYA Senin-Kamis, 09:00-15:00 WIB. Exception butuh approval @reza atau @lead-engineer + standby coverage minimum 4 jam post-deploy.

Exception 4 kali dalam 12 bulan:

  • 2x security patch critical (zero-day di dependency)
  • 1x DB schema migration yang butuh maintenance window weekend
  • 1x deploy fitur dengan event timing fixed (campaign customer)

2. --no-verify tetap haram

Saya hapus alias --no-verify di shell config tim. Plus pre-commit hook tambahan: kalau --no-verify di-detect di reflog, kirim notif ke #ops dengan nama commit author. Public shaming gentle.

Dalam 12 bulan: 0 commit dengan --no-verify di main branch.

3. Pattern Stabilize → Investigate → Fix → Deploy

Ini lebih culture daripada teknis. Saat insident, tim default ke rollback dulu, baru investigate dengan kepala dingin.

Saya track MTTR (Mean Time To Resolve) per incident:

  • Bulan 1-3 setelah postmortem: MTTR 38 menit avg
  • Bulan 10-12: MTTR 14 menit avg

Pendek karena: (a) auto-rollback handle 60% incident tanpa intervensi manual, (b) tim tahu rollback dulu, debug nanti.

Satu kali deploy Jumat (sengaja)

Bulan ke-9, ada kebutuhan deploy patch security ke library yang Critical CVE dengan exploit public. Saya bisa tunggu Senin (CVE belum di-exploit liar di Indonesia), atau deploy Jumat 14:00.

Saya pilih Jumat 14:00. Dengan safety net:

  1. Tim standby: saya + 1 engineer cover 19:00 WIB Jumat sampai 12:00 Sabtu.
  2. Canary slower: 5% selama 30 menit, bukan 10 menit default.
  3. Communication: notify customer support tim, briefing skenario rollback.
  4. Personal: saya cancel jadwal nonton bioskop Jumat malam (klise tapi true).

Hasil: deploy OK, tidak ada incident. Sabtu pagi saya nge-kopi dengan istri seperti biasa.

Aturan “tidak deploy Jumat” bukan superstition — itu trade-off antara velocity dan recovery cost. Saat ada kebutuhan dan safety net memadai, exception OK. Yang tidak OK: deploy Jumat karena terbiasa cepat-cepat tutup minggu.

Angka 12 bulan

MetricSebelum (12 bulan lalu)Sekarang
Deploy frequency2-3/minggu5-8/hari
Incident production-impacting4 (12 bulan)7 (12 bulan)*
MTTR38 menit avg14 menit avg
Deploy yang di-rollback~12%~2.4%
Customer-reported bug236
User yang impact 1+ incident47 unique12 unique

*Incident lebih banyak secara absolut karena deploy 30x lebih sering. Per-deploy rate jauh lebih kecil.

Pelajaran lebih dalam

1. Aturan tanpa automation = harapan

“Jangan deploy Jumat” sebagai aturan tertulis: gagal kalau cuma tergantung disiplin. Saya 12 bulan lalu disiplin saya gagal sendiri.

Yang work: pipeline yang refuse deploy Jumat default. Workflow Actions saya punya guard:

- name: Check deploy time
  run: |
    DAY=$(TZ=Asia/Jakarta date +%u)
    HOUR=$(TZ=Asia/Jakarta date +%H)
    if [ "$DAY" -eq 5 ] && [ "$HOUR" -ge 15 ]; then
      if [ -z "$ALLOW_FRIDAY" ]; then
        echo "Friday deploy after 15:00 requires ALLOW_FRIDAY=1"
        exit 1
      fi
    fi

ALLOW_FRIDAY set via workflow_dispatch manual dengan approval reviewer. Tidak bisa dengan git push biasa.

2. Canary > smoke test

Smoke test cuma cek “site up?” — itu lemah. Canary kasih sinyal real (apakah user real menggunakan tanpa error?). Smoke test bisa salah (lihat false negative di postmortem original). Canary dengan SLO threshold lebih representatif.

3. Anonymized production data di staging adalah investasi terbesar

Sekitar 8 jam setup awal, 2 jam tuning script anonymize. Tapi catch 2 bug critical dalam setahun yang akan jadi incident kalau langsung ke production. ROI tinggi.

4. Tim kecil butuh otomasi lebih, bukan disiplin lebih

Tim 4 engineer ngga akan match disiplin tim 40 engineer dengan SRE dedicated. Compensate dengan automation. Setiap “kami akan ingat untuk…” adalah liabilitas masa depan.

Yang masih bikin saya tidak tidur

Satu hal yang belum solved: deploy yang impactnya tidak langsung visible. Misal, deploy yang slowly leak memory dan baru manifest setelah 12 jam. Canary 22 menit tidak catch ini.

Saya pasang alert untuk memory growth abnormal (RSS naik > 30% dalam 6 jam), tapi belum punya proper longitudinal canary. Masih PR ke diri sendiri.

Verdict

12 bulan postmortem dari postmortem: pipeline lebih matang, tim lebih disiplin, frekuensi deploy 3-4x lebih tinggi dengan rate insident lebih rendah. Investasi otomasi (canary, auto-rollback, anonymized staging) bayar diri sendiri.

Saya masih tidak deploy Jumat sore default. Tapi sekarang kalau harus, saya bisa — karena safety net memang dirancang untuk itu. Yang dulu rasa takut deploy, sekarang rasa hati-hati.

Bukan magic. Disiplin + automation, dengan kesabaran 12 bulan untuk lihat hasil.

Ditulis oleh Reza Pradipta