Zero-downtime deploy pada Laravel bukan sekadar menjalankan php artisan down lalu up. Tujuan utamanya adalah merilis kode baru tanpa memutus trafik aktif, sambil memastikan aplikasi sehat, migrasi database aman, dan ada jalur rollback yang realistis jika terjadi masalah.
Prinsip pentingnya adalah memisahkan deploy aplikasi dari perubahan database yang berisiko, memakai migrasi yang maju-kompatibel, melakukan health check dan smoke test setelah rilis, serta menyiapkan rollback yang tidak bergantung pada harapan bahwa semua migrasi bisa dibalik dengan aman. Artikel ini membahas urutan rilis yang praktis dan netral terhadap vendor CI/CD maupun platform hosting.
Mengapa zero-downtime deploy di Laravel sering gagal
Banyak deploy gagal bukan karena proses copy file atau restart service, melainkan karena ketidaksesuaian antara versi kode dan skema database. Contoh paling umum:
- Kode baru langsung membaca kolom yang belum dibuat.
- Migrasi menghapus atau mengganti nama kolom yang masih dipakai worker lama.
- Queue worker lama tetap memproses job dengan payload lama ketika kode baru sudah aktif.
- Konfigurasi cache, route cache, atau container cache tidak direfresh dengan urutan yang benar.
- Health check hanya memeriksa respons HTTP 200, tetapi tidak mendeteksi kegagalan koneksi database atau queue.
Karena itu, zero-downtime deploy harus dipandang sebagai proses rilis bertahap, bukan satu perintah tunggal.
Prinsip desain rilis aman
1. Pisahkan deploy kode dari migrasi database
Jangan anggap deploy kode dan php artisan migrate selalu aman dijalankan bersamaan. Perubahan skema tertentu aman, tetapi sebagian lain berisiko memblokir query, mematahkan kompatibilitas, atau memperbesar blast radius saat rollback.
Pendekatan yang lebih aman:
- Rilis kode yang masih kompatibel dengan skema lama.
- Jalankan migrasi yang forward-compatible.
- Aktifkan pembacaan/penulisan ke skema baru secara bertahap.
- Setelah stabil, baru lakukan pembersihan skema lama pada rilis berikutnya.
2. Gunakan migrasi maju-kompatibel
Migrasi maju-kompatibel berarti versi lama dan versi baru aplikasi masih bisa berjalan selama masa transisi. Contohnya:
- Aman: menambah kolom nullable atau memberi default yang sesuai.
- Lebih aman: menambah index baru sebelum query baru bergantung padanya.
- Berisiko: rename kolom yang masih dibaca kode lama.
- Sangat berisiko: drop kolom atau ubah tipe data secara destruktif dalam deploy yang sama.
Pola umum yang sering dipakai adalah expand and contract:
- Expand: tambah struktur baru tanpa menghapus yang lama.
- Deploy kode yang bisa membaca struktur lama maupun baru.
- Lakukan backfill data jika diperlukan.
- Alihkan trafik/fitur ke struktur baru.
- Contract: hapus struktur lama pada rilis terpisah setelah terbukti aman.
3. Rollback aplikasi harus cepat, rollback database harus terkendali
Rollback aplikasi idealnya cukup mengembalikan symlink, image, atau artefak ke versi sebelumnya. Itu cepat dan rendah risiko.
Sebaliknya, rollback database sering kali tidak aman jika dilakukan otomatis. Migrasi yang menghapus data, mengubah tipe kolom, atau melakukan backfill besar bisa sulit dibalik tanpa kehilangan data. Karena itu:
- Utamakan desain migrasi yang tidak memaksa rollback database segera.
- Jangan mengandalkan
migrate:rollbacksebagai satu-satunya strategi penyelamatan. - Siapkan prosedur rollback DB yang eksplisit dan teruji untuk perubahan berisiko tinggi.
Urutan zero-downtime deploy yang direkomendasikan
Berikut urutan rilis yang umumnya aman untuk aplikasi Laravel dengan trafik aktif.
Tahap 1: Pre-deploy validation
Sebelum artefak dipromosikan ke production, jalankan validasi minimum berikut:
- Unit test dan integration test penting.
- Linting dan static analysis bila tersedia.
- Build artefak sekali, lalu pakai artefak yang sama untuk semua environment.
- Verifikasi file konfigurasi yang wajib ada.
- Review migrasi: apakah additive, backward-compatible, atau destruktif.
Jika ada migrasi destruktif, tandai rilis sebagai butuh prosedur khusus, bukan deploy rutin.
Tahap 2: Siapkan release baru
Deploy release baru ke direktori atau image terpisah tanpa langsung mengalihkan trafik. Pada tahap ini, lakukan:
- Install dependency produksi.
- Generate atau warmup cache yang diperlukan.
- Pastikan secret dan environment variable lengkap.
- Jangan hapus release lama sebelum release baru dinyatakan sehat.
Jika memakai worker queue, siapkan juga restart terkontrol setelah kode baru aktif.
Tahap 3: Jalankan migrasi yang aman
Jalankan hanya migrasi yang sudah dinilai kompatibel. Untuk perubahan berat, pertimbangkan menjalankannya di luar jalur deploy utama atau dalam maintenance operation terpisah.
Contoh migrasi additive yang relatif aman:
Schema::table('orders', function ($table) {
$table->string('external_reference')->nullable()->index();
});Contoh perubahan yang sebaiknya tidak digabung dengan switch trafik dalam satu langkah:
- Drop kolom lama.
- Rename kolom yang dibaca kode lama.
- Backfill jutaan baris secara sinkron di proses deploy.
- Perubahan index besar yang berpotensi memblokir write pada database tertentu.
Tahap 4: Switch trafik tanpa maintenance penuh
Pada zero-downtime deploy, strategi maintenance bukan berarti seluruh aplikasi dimatikan. Yang dibutuhkan adalah pengalihan trafik yang atomik ke release baru, sambil release lama tetap tersedia sebagai kandidat rollback cepat.
Implementasi teknisnya bisa berbeda-beda, misalnya:
- Symlink
currentyang dipindahkan ke release baru. - Rolling update pada beberapa instance aplikasi.
- Blue-green deployment dengan switch trafik di load balancer.
Yang penting, perpindahan harus:
- Cepat.
- Bisa dibalik.
- Tidak menghapus release lama lebih dulu.
Tahap 5: Health check aplikasi
Setelah trafik dialihkan, lakukan health check yang lebih bermakna daripada sekadar GET /. Endpoint health check sebaiknya memeriksa dependensi minimum yang memang menentukan apakah aplikasi layak menerima trafik.
Contoh implementasi sederhana di Laravel:
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
Route::get('/health', function () {
try {
DB::select('SELECT 1');
return response()->json([
'status' => 'ok',
'checks' => [
'database' => 'ok',
],
]);
} catch (\Throwable $e) {
report($e);
return response()->json([
'status' => 'fail',
'checks' => [
'database' => 'fail',
],
], 503);
}
});Hal yang perlu diperhatikan:
- Health check jangan terlalu berat atau menyentuh banyak service yang tidak wajib untuk melayani request utama.
- Jika memakai cache, queue, atau object storage sebagai komponen kritis, tambahkan cek seperlunya.
- Jangan bocorkan detail sensitif exception ke respons publik.
Bedakan juga dua jenis endpoint:
- Liveness check: proses masih hidup.
- Readiness check: instance siap menerima trafik.
Untuk deploy, readiness biasanya lebih penting.
Tahap 6: Smoke test pascadeploy
Health check hanya membuktikan aplikasi hidup, belum membuktikan alur bisnis utama berjalan. Karena itu, jalankan smoke test setelah deploy. Pilih 3-5 skenario paling kritis, misalnya:
- Login atau autentikasi token.
- Endpoint API utama merespons benar.
- Proses create/read pada resource inti.
- Halaman atau route paling sering diakses.
Contoh script sederhana berbasis shell:
set -e
curl -fsS https://app.example.com/health > /dev/null
curl -fsS https://app.example.com/api/profile \
-H "Authorization: Bearer $SMOKE_TEST_TOKEN" > /dev/nullSmoke test harus cepat, deterministik, dan tidak bergantung pada data yang mudah berubah.
Tahap 7: Restart worker secara terkendali
Jika aplikasi menggunakan queue worker, jangan lupakan proses ini. Worker lama dapat terus hidup dan memproses job dengan kode usang. Pada Laravel, pola umumnya adalah memberi sinyal agar worker memuat ulang setelah job berjalan selesai.
php artisan queue:restartPerintah ini lebih aman daripada mematikan worker secara kasar, tetapi tetap pastikan supervisor atau process manager Anda menghidupkan worker baru dengan release terbaru.
Contoh struktur pipeline CI/CD
Berikut contoh struktur pipeline yang netral terhadap vendor:
stages:
- validate
- build
- deploy_prepare
- migrate_safe
- switch_traffic
- verify
- finalize
validate:
- composer install --no-interaction
- php artisan test
build:
- composer install --no-dev --optimize-autoloader
- php artisan config:cache
- php artisan route:cache
- package release artifact
deploy_prepare:
- upload artifact to target
- extract to new release directory
- link shared storage and env
migrate_safe:
- php artisan migrate --force
switch_traffic:
- point current release to new artifact
verify:
- curl -fsS https://app.example.com/health
- run smoke tests
- php artisan queue:restart
finalize:
- keep previous release for rollback
- notify deployment resultPoin penting dari pipeline di atas:
- Build sekali, deploy artefak yang sama.
- Verification dilakukan setelah switch trafik, bukan hanya sebelum deploy.
- Previous release dipertahankan untuk rollback cepat.
Strategi migrasi maju-kompatibel yang realistis
Menambah kolom baru
Kasus paling aman adalah menambah kolom nullable atau memiliki default yang masuk akal. Kode baru bisa mulai menulis ke kolom itu tanpa merusak kode lama.
Mengganti nama kolom
Jangan langsung rename jika versi lama aplikasi masih berjalan. Lebih aman:
- Tambah kolom baru.
- Tulis ke kolom lama dan baru sementara waktu.
- Baca dari kolom baru, fallback ke lama bila perlu.
- Backfill data lama.
- Hapus kolom lama pada rilis berikutnya.
Mengubah format data
Jika format berubah, misalnya dari string ke JSON atau dari satu kolom menjadi beberapa kolom, gunakan fase transisi. Hindari deploy yang mengharuskan semua data lama ditransformasi sebelum aplikasi bisa berjalan.
Backfill data
Jangan lakukan backfill besar di migration jika durasinya tidak terprediksi. Lebih aman memindahkannya ke job terpisah, command khusus, atau batch bertahap yang bisa dipantau dan dihentikan bila ada masalah.
Kapan rollback harus dilakukan
Tidak semua error pascadeploy perlu rollback. Kadang cukup perbaikan konfigurasi kecil atau restart worker. Namun ada tanda-tanda yang jelas bahwa rollback aplikasi harus dilakukan segera:
- Lonjakan error 5xx setelah switch trafik.
- P95/P99 latency meningkat tajam dan stabil.
- Endpoint kritis gagal di smoke test.
- Query error karena skema tidak cocok dengan kode.
- Queue failure melonjak pada job bisnis utama.
- Pengguna tidak bisa login, checkout, atau memakai fungsi inti.
Rollback sebaiknya dipicu berdasarkan indikator objektif, bukan intuisi semata. Tentukan ambang dan durasi observasi singkat, misalnya beberapa menit pertama setelah deploy adalah masa evaluasi ketat.
Jika masalah berkaitan dengan skema database yang sudah berubah, rollback aplikasi mungkin tetap aman hanya jika kode lama masih kompatibel dengan skema baru. Inilah alasan migrasi maju-kompatibel sangat penting.
Rollback aplikasi dan rollback database yang terkendali
Rollback aplikasi
Rollback aplikasi idealnya:
- Mengembalikan release pointer ke versi sebelumnya.
- Merestart atau me-reload worker agar memakai kode lama.
- Memverifikasi health check dan smoke test pada versi yang dipulihkan.
Contoh alur rollback aplikasi:
- Pause promosi release lebih lanjut.
- Alihkan trafik ke release sebelumnya.
- Jalankan
php artisan queue:restart. - Ulangi health check dan smoke test.
- Bekukan perubahan tambahan sampai penyebab insiden jelas.
Rollback database
Rollback database perlu lebih hati-hati. Jangan langsung menjalankan:
php artisan migrate:rollback --forcePerintah itu mungkin tepat untuk kasus sederhana, tetapi bisa salah untuk situasi production yang kompleks. Pertimbangkan hal berikut:
- Apakah migrasi menghapus data?
- Apakah ada write baru setelah skema berubah?
- Apakah rollback akan memotong data yang sudah ditulis versi baru?
- Apakah migrasi dibungkus transaksi, dan apakah engine database mendukungnya untuk operasi tersebut?
Pendekatan yang lebih aman untuk perubahan berisiko tinggi:
- Siapkan runbook rollback DB per jenis perubahan.
- Jika perlu, buat migrasi kompensasi, bukan rollback otomatis.
- Lakukan restore dari backup hanya untuk skenario berat, karena ini biasanya berdampak besar dan berisiko kehilangan data terbaru.
Contoh prinsip runbook:
- Nilai apakah rollback aplikasi saja cukup.
- Jika tidak, hentikan write yang memperparah inkonsistensi.
- Verifikasi status data dan skema.
- Jalankan perubahan kompensasi yang sudah disiapkan.
- Validasi data kritis sebelum trafik penuh dikembalikan.
Observability minimum yang wajib ada saat deploy
Tanpa observability, zero-downtime deploy hanya terlihat aman. Minimum yang sebaiknya dipantau selama dan setelah rilis:
Metrik aplikasi
- Error rate 4xx/5xx, terutama 5xx.
- Latency median dan tail latency seperti P95/P99.
- Request throughput.
- Jumlah instance sehat vs tidak sehat.
Metrik database
- Kegagalan koneksi.
- Slow query.
- Lock atau contention yang meningkat.
- Replikasi tertinggal jika ada replica.
Metrik queue
- Jumlah job gagal.
- Waktu tunggu queue.
- Retry yang melonjak.
Log yang wajib diperiksa
- Exception aplikasi pascadeploy.
- Error migrasi.
- Query error seperti unknown column, invalid input syntax, atau deadlock.
- Log worker yang gagal memuat release baru.
Gunakan correlation ID atau request ID jika tersedia agar pelacakan error lintas layer lebih mudah.
Checklist sebelum rilis
- Artefak build sudah lolos test.
- Release notes menjelaskan perubahan skema dan risiko.
- Migrasi sudah diklasifikasikan: additive, transisional, atau destruktif.
- Rollback aplikasi sudah jelas caranya dan pernah diuji.
- Rollback database memiliki runbook bila perubahan DB berisiko.
- Health check dan smoke test siap dijalankan otomatis.
- Monitoring dashboard dan log mudah diakses saat deploy.
- Queue worker restart strategy sudah dipastikan.
- Backup atau snapshot sesuai kebijakan tersedia sebelum perubahan berat.
Checklist setelah rilis
- Health check lulus.
- Smoke test skenario utama lulus.
- Error rate dan latency stabil.
- Tidak ada anomali query error atau lock database.
- Queue failure tidak melonjak.
- Worker sudah memproses dengan release terbaru.
- Tim mencatat waktu deploy, versi rilis, dan hasil verifikasi.
Kesalahan umum yang perlu dihindari
- Menganggap
artisan downadalah solusi zero-downtime. - Menjalankan migrasi destruktif di jalur deploy normal.
- Menghapus release lama terlalu cepat.
- Tidak merestart worker queue setelah rilis.
- Membuat health check yang terlalu dangkal atau terlalu berat.
- Tidak memisahkan masalah aplikasi dari masalah database saat insiden.
- Mengandalkan rollback otomatis tanpa menguji kompatibilitas data.
Debugging cepat saat deploy bermasalah
Jika deploy baru saja selesai dan error muncul, urutan diagnosis cepat yang praktis adalah:
- Cek dashboard error rate dan latency.
- Buka log aplikasi untuk exception pertama yang meningkat.
- Verifikasi health check dan endpoint smoke test secara manual.
- Cek apakah worker masih menjalankan release lama.
- Periksa query error yang mengarah ke mismatch skema.
- Jika dampak tinggi dan penyebab belum jelas, rollback aplikasi lebih dulu.
Tujuannya bukan langsung menemukan akar masalah, tetapi mengurangi durasi gangguan secepat mungkin.
Postmortem ringan setelah insiden deploy
Setelah insiden tertangani, lakukan postmortem singkat. Tidak perlu panjang, tetapi harus menghasilkan tindakan nyata.
Format sederhana
- Apa yang berubah: commit, fitur, migrasi, perubahan infra.
- Dampak: endpoint terdampak, durasi, pengguna terdampak.
- Deteksi: bagaimana insiden ditemukan, berapa lama.
- Akar masalah: mismatch skema, cache basi, worker lama, konfigurasi salah, dan sebagainya.
- Respons: rollback, hotfix, migrasi kompensasi.
- Pencegahan: test tambahan, perubahan pipeline, runbook baru.
Tindakan pencegahan yang efektif
- Tambahkan pemeriksaan kompatibilitas migrasi dalam code review.
- Buat daftar perubahan DB yang dilarang di deploy rutin.
- Otomatiskan smoke test pascadeploy.
- Uji rollback aplikasi secara berkala, bukan hanya saat insiden.
- Tambahkan alert untuk spike error setelah deploy.
- Gunakan feature flag untuk aktivasi bertahap fitur berisiko.
Penutup
Laravel zero-downtime deploy dengan health check dan rollback database yang aman bergantung pada disiplin urutan rilis, bukan pada satu tool tertentu. Kunci utamanya adalah: deploy kode yang kompatibel, jalankan migrasi yang aman, alihkan trafik secara reversibel, verifikasi lewat health check dan smoke test, pantau metrik penting, lalu siapkan rollback aplikasi yang cepat dan rollback database yang terkendali.
Jika Anda hanya mengambil satu pelajaran dari panduan ini, ambillah yang ini: rancang perubahan database agar versi lama dan versi baru aplikasi bisa hidup berdampingan sementara waktu. Dengan itu, sebagian besar insiden deploy akan jauh lebih mudah ditangani tanpa downtime yang nyata.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!