Manajemen Cron Job Skala Enterprise: Mencegah Race Condition di Backend
1. Titik Awal Masalah: Mengapa Arsitektur Lama Sering Ambruk di Produksi
Pukul dua pagi, pagerduty berdering nyaring. Notifikasi Slack menyala merah terang: โDatabase connection pool exhaustedโ. Sebagai engineer yang sudah belasan tahun berkecimpung di dunia infrastruktur skala besar, saya langsung tahu apa yang terjadi. Bukan karena serangan DDoS, bukan pula karena query SQL yang kurang index. Penyebabnya jauh lebih klasik namun sering diabaikan: cron job penagihan berlangganan yang berjalan serentak di tiga server backend berbeda karena autoscaling baru saja melakukan scale-out.
Di era arsitektur monolitik lama, kita terbiasa menulis skrip PHP atau Node.js sederhana, lalu mendaftarkannya ke crontab lokal: 0 2 * * * /usr/bin/php /var/www/html/artisan schedule:run. Cara ini ampuh selama aplikasi Anda berjalan di satu mesin tunggal. Namun, begitu bisnis bertumbuh dan sistem bertransformasi menjadi kluster terdistribusi di balik load balancer Nginx dengan beberapa instance backend, pendekatan naif ini menjelma menjadi bom waktu.
Setiap server yang menjalankan skrip cron secara independen akan memicu proses yang sama di detik yang sama. Akibatnya? Race condition massal. Transaksi finansial ganda diproses, saldo pengguna terpotong dua kali, dan tabel database mengalami deadlock karena berebut baris data. Kita tidak bisa lagi mempercayai jam internal server begitu saja. Menjaga agar background tasks berjalan tepat satu kali (exactly-once execution) di lingkungan terdistribusi menuntut pergeseran paradigma arsitektural yang radikal, yang akan kita bedah perlahan dari akar masalah hingga eksekusi kodenya.