Programming Tutorial Laravel Backend 04 August 2025

Tutorial Laravel Migration Zero Downtime untuk Pemula

Tutorial Laravel Migration Zero Downtime untuk Pemula
Bagikan:

Bayangkan kamu punya aplikasi Laravel yang melayani ribuan pengguna setiap hari. Tiba-tiba kamu perlu mengubah struktur database—namun kalau sampai aplikasi down walau cuma beberapa menit, bisa-bisa pengguna kabur dan bisnis rugi. Gimana cara mengatasinya?

Hari ini kita akan belajar teknik yang dipakai perusahaan besar seperti Shopify dan GitHub untuk mengubah database tanpa membuat aplikasi mati total. Tekniknya disebut Zero-Downtime Migration menggunakan strategi Double Write dan Backfill.

Kenapa Harus Belajar Zero-Downtime Migration?

Sebelum masuk ke teknis, mari kita pahami dulu mengapa ini penting. Kalau kamu jalanin migration biasa di aplikasi yang ramai, bisa terjadi:

  • Table terkunci dan user dapat error “table is locked”
  • Aplikasi down beberapa menit (atau lebih buruk lagi, berjam-jam)
  • User kabur karena frustrasi
  • Revenue turun drastis

Makanya, untuk aplikasi production yang sudah punya traffic tinggi, kita butuh cara yang lebih aman.

Apa Itu Double Write dan Backfill?

Konsep dasarnya sederhana: daripada langsung mengubah struktur database yang ada, kita buat struktur baru dulu, lalu secara bertahap memindahkan data. Ibaratnya seperti renovasi rumah—kamu nggak langsung bongkar semuanya, tapi bikin ruang baru dulu, baru kemudian pindah perabotan pelan-pelan.

Persiapan Sebelum Mulai

Pastikan kamu sudah punya:

  • Laravel project yang sudah running
  • Database dengan data yang cukup banyak (untuk testing)
  • Environment staging untuk testing
  • Backup database (ini wajib!)
Langkah 1: Tambah Kolom Baru Tanpa Hapus yang Lama

Misalnya kamu punya table products seperti ini:

// Migration awal
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('product_name');
    $table->integer('price'); // Ini yang mau diubah ke decimal
    $table->timestamps();
});

Sekarang kamu mau:

  1. Tambah kolom slug
  2. Ubah price dari integer ke decimal

Jangan langsung alter table! Buat migration baru yang menambah kolom, bukan mengubah:

// Migration baru - 2025_08_03_160000_add_new_columns_to_products.php
Schema::table('products', function (Blueprint $table) {
    $table->string('slug')->nullable()->after('product_name');
    $table->decimal('new_price', 10, 2)->nullable()->after('price');
});

Kenapa pakai nullable()? Biar data yang sudah ada tetap bisa jalan normal tanpa error.

Tips Pro: Selalu Preview Dulu Migration

Sebelum jalanin migration, cek dulu SQL yang akan dieksekusi:

php artisan migrate --pretend

Command ini akan tampilkan SQL query yang akan dijalankan tanpa benar-benar menjalankannya. Ini penting banget untuk memastikan nggak ada query yang berbahaya.

Langkah 2: Implementasi Double Write

Sekarang kita perlu memastikan setiap kali ada perubahan data, kita tulis ke kolom lama DAN kolom baru. Di model Product, tambahkan:

class Product extends Model
{
    protected $fillable = [
        'product_name', 
        'price', 
        'new_price', 
        'slug'
    ];

    // Event listener untuk sync data
    protected static function booted()
    {
        static::saving(function ($product) {
            // Kalau price berubah, sync ke new_price
            if ($product->isDirty('price')) {
                $product->new_price = $product->price;
            }
            
            // Auto-generate slug kalau product_name berubah
            if ($product->isDirty('product_name')) {
                $product->slug = Str::slug($product->product_name);
            }
        });
    }
}

Dengan begini, setiap kali ada data baru atau update, otomatis tersync ke kolom baru.

Langkah 3: Backfill Data yang Sudah Ada

Nah, sekarang kita perlu isi kolom baru dengan data dari kolom lama. Buat Artisan command khusus:

// Buat command: php artisan make:command BackfillProductsCommand
// Atau langsung pakai closure command di routes/console.php

Artisan::command('backfill:products', function () {
    $this->info('Memulai backfill data products...');
    
    // Gunakan chunk untuk handle data besar
    Product::whereNull('new_price') // Hanya yang belum diisi
        ->orWhereNull('slug')
        ->chunk(1000, function ($products) {
            foreach ($products as $product) {
                $product->update([
                    'new_price' => $product->price,
                    'slug' => Str::slug($product->product_name),
                ]);
            }
            
            $this->info("Processed {$products->count()} products...");
        });

    $this->info('Backfill selesai!');
});

Jalankan command:

php artisan backfill:products

Kenapa pakai chunk()? Biar nggak kehabisan memory kalau datanya jutaan record.

Langkah 4: Siapkan Rencana Rollback

Ini yang sering dilupain tapi super penting! Selalu siapkan cara untuk mundur kalau ada masalah:

// Migration rollback
Schema::table('products', function (Blueprint $table) {
    $table->dropColumn(['new_price', 'slug']);
});

Untuk rollback:

php artisan migrate:rollback --step=1

Langkah 5: Testing dan Monitoring

Sebelum lanjut ke production:

  1. Test di staging environment dengan data yang mirip production
  2. Monitor performa dengan Laravel Telescope atau tools monitoring lain
  3. Cek memory usage saat jalanin backfill
  4. Pastikan double write berjalan dengan coba create/update data

Langkah 6: Switch ke Struktur Baru

Kalau semua aman dan data sudah tersync sempurna:

  1. Update kode aplikasi untuk pakai kolom baru:
// Ubah semua reference dari 'price' ke 'new_price'
// Dan mulai pakai 'slug' dalam query

// Contoh di controller:
public function index()
{
    return Product::select(['id', 'product_name', 'new_price as price', 'slug'])
        ->get();
}
  1. Buat migration final untuk hapus kolom lama:
Schema::table('products', function (Blueprint $table) {
    $table->dropColumn('price'); // Hapus kolom lama
    $table->renameColumn('new_price', 'price'); // Rename ke nama asli
});

Switch Selesai, Zero Downtime!

Selamat! Kamu berhasil mengubah struktur database tanpa membuat aplikasi down sama sekali.

Tips Penting yang Wajib Diingat

Selalu test di staging dulu - Jangan pernah langsung ke production ✅ Monitor performa - Pakai Laravel Telescope untuk pantau query ✅ Siapkan rollback plan - Better safe than sorry! ✅ Gunakan --pretend - Preview migration sebelum jalanin ✅ Chunk data besar - Hindari memory overflow ✅ Backup database - Ini wajib hukumnya!

Kapan Sebaiknya Pakai Teknik Ini?

Teknik zero-downtime migration cocok untuk:

  • Table dengan jutaan record
  • Aplikasi dengan traffic tinggi yang nggak boleh down
  • Perubahan tipe data kolom (misal: integer ke decimal)
  • Menambah foreign key atau index di table besar
  • Aplikasi e-commerce, banking, atau sistem critical lainnya

Kapan Nggak Perlu Ribet?

Kalau aplikasimu masih development atau traffic rendah, migration biasa sudah cukup. Teknik ini lebih untuk aplikasi production yang udah established.

Kesalahan yang Sering Terjadi Pemula

  1. Lupa backup database - Fatal error!
  2. Langsung alter column - Bisa bikin table lock
  3. Nggak test di staging - Recipe for disaster
  4. Lupa implement double write - Data jadi nggak sync
  5. Backfill data terlalu besar sekaligus - Server bisa hang

Tools yang Membantu

  • Laravel Telescope: Monitor query dan performance
  • Laravel Horizon: Kalau pakai queue untuk background processing
  • Database monitoring tools: Untuk track performance database

Langkah Selanjutnya

Setelah menguasai basic zero-downtime migration, kamu bisa explore:

  • Blue-green deployment
  • Database sharding techniques
  • Advanced indexing strategies
  • Performance optimization untuk large datasets

Kesimpulan

Zero-downtime migration mungkin terlihat ribet di awal, tapi ini investment yang worth it untuk aplikasi production. Dengan teknik Double Write dan Backfill, kamu bisa dengan aman mengubah struktur database tanpa bikin user frustrasi karena downtime.

Ingat: “Measure twice, cut once” - selalu test dan planning matang sebelum eksekusi. Database adalah jantung aplikasi, jadi harus extra hati-hati.

Sekarang kamu sudah tahu caranya. Mulai dari aplikasi kecil dulu, baru nanti kalau sudah confidence, pakai di project besar. Happy coding!