L
Cron 🚨 Post-Mortem & Incident Runbook â€ĸ Literally Web ID

Arsitektur Background Worker Skala Enterprise Menggunakan Redis dan Supervisor

âąī¸ 15 menit baca â€ĸ 📅 20 Oct 2026 â€ĸ đŸ‘ī¸ 2 views
Arsitektur Background Worker Skala Enterprise Menggunakan Redis dan Supervisor
🔊 Dengarkan Artikel Ini

1. Alarm Tengah Malam: Saat Layanan Produksi Mulai Tumbang

Pukul 02.14 WIB. Suar melengking dari PagerDuty memecah keheningan kamar saya. Layar ponsel mendadak menyala terang, menampilkan notifikasi merah menyala: High Error Rate on Production Web Cluster. Belum sempat saya menyeduh kopi hitam, dashboard Grafana sudah menyuguhkan pemandangan horor berupa grafik latensi API yang melompat vertikal dari 120 milidetik menjadi 14 detik, dibarengi lonjakan penggunaan memori pada Redis instance utama yang menyentuh angka 98%.

Di balik layar, jutaan job asinkron seperti pengiriman email transaksional, pemrosesan webhook pembayaran dari payment gateway, dan sinkronisasi data inventaris e-commerce sedang menumpuk layaknya antrean BBM bersubsidi. Arsitektur background worker yang selama ini berjalan mulus tiba-tiba mengalami choke. Proses worker PHP-FPM di balik layar berguguran karena kehabisan alokasi memori, sementara Supervisor yang bertugas menjaga mereka tetap hidup justru kewalahan melakukan spawn proses baru akibat resource starvation.

[!WARNING] Membiarkan Redis mencapai batas maksimal memori tanpa konfigurasi kebijakan eviction yang tepat (seperti noeviction) adalah jalan pintas menuju bencana Out-Of-Memory (OOM) Killer yang akan mematikan proses database in-memory secara paksa.

Kepanikan awal ini harus segera diredam dengan kepala dingin. Sebagai engineer yang telah bertahun-tahun bergulat dengan infrastruktur skala besar, saya tahu betul bahwa menyalahkan aplikasi saja tidak cukup. Kita harus turun ke ruang mesin, menyelami log mentah, dan membedah apa yang sebenarnya terjadi di balik layar.

2. Jejak Digital: Menelusuri Anomali Log & Lonjakan Metrik

Langkah pertama yang saya ambil adalah masuk ke server bastion menggunakan SSH, lalu menerobos masuk ke node worker melalui jaringan internal. Jari-jemari langsung menari di atas terminal untuk memeriksa kesehatan sistem secara real-time menggunakan htop dan memantau log Supervisor.

# Masuk ke direktori log Supervisor untuk memantau proses worker yang sekarat
cd /var/log/supervisor/
tail -f worker-process-err.log | grep -i "Allowed memory size exhausted"

Baris-baris log langsung memuntahkan pesan error yang sudah tidak asing lagi, namun dalam skala yang mengerikan:

[2023-10-24 02:15:30] production.ERROR: FatalErrorException: Allowed memory size of 536870912 bytes exhausted (tried to allocate 20480 bytes) in /var/www/html/app/Jobs/ProcessBulkOrders.php on line 114

Ternyata, job ProcessBulkOrders yang bertugas menarik data ribuan transaksi sekaligus ke dalam satu payload memori menjadi biang keladi utama Memory Leak. Karena job tersebut gagal mengeksekusi dengan sukses, Redis secara otomatis mengembalikan item tersebut ke dalam antrean (queue) untuk dicoba ulang (retry). Siklus ini berulang ribuan kali per detik, menciptakan infinite loop yang secara agresif melahap sisa RAM yang ada.

[!TIP] Gunakan perintah redis-cli monitor hanya untuk debugging kilat di staging environment. Di production, utilitas ini dapat melumpuhkan performa Redis seketika karena beban I/O yang masif.

Melalui pemeriksaan lebih lanjut pada CLI Redis, ditemukan fakta bahwa antrean default membengkak hingga 450.000 unprocessed jobs. Angka yang fantastis untuk sistem yang kapasitas normal prosesnya hanya 50 job per detik.

3. Membongkar Biang Kerok: Akar Masalah yang Sebenarnya

Setelah menarik napas panjang dan membedah struktur kode di balik job tersebut, akar masalahnya menjadi sangat terang benderang. Ada tiga dosa besar arsitektural yang dilakukan pada implementasi awal:

  1. Monolitik Payload: Seluruh objek Eloquent Model beserta relasinya di-serialize dan dimasukkan mentah-mentah ke dalam Redis list sebagai string JSON yang sangat besar.
  2. Absennya Backoff Strategy & Max Tries: Job dikonfigurasi untuk terus retry tanpa jeda waktu (exponential backoff), membuat Redis dan database relasional (MySQL) lumpuh karena dihantam ribuan kueri paralel secara konstan.
  3. Salah Konfigurasi Supervisor: Parameter numprocs diset terlalu tinggi (50 proses per server) tanpa memperhitungkan batas maksimal koneksi database, sehingga koneksi MySQL langsung habis (Too many connections).

Perbandingan antara desain yang rapuh dan desain yang tahan banting dapat dirangkum sebagai berikut:

Aspek Arsitektur Desain Rapuh (Sebelumnya) Desain Tahan Banting (Target)
Payload Redis Menyimpan seluruh objek data (berat) Hanya menyimpan ID unik / Primary Key
Retry Policy Instan tanpa jeda (Infinite loop) Exponential Backoff + Max Tries limit
Dead Letter Queue Tidak ada (Job gagal hilang/looping) Tersedia (Dipindahkan ke DLQ setelah X gagal)
Process Manager Supervisor over-provisioned Supervisor terkalibrasi dengan Resource Limits

Memahami kelemahan ini menuntun kita pada langkah penyelamatan darurat yang harus dieksekusi dalam hitungan detik.

4. Tindakan Darurat: Menghidupkan Kembali Layanan dalam Hitungan Menit

Situasi genting menuntut tindakan bedah minor yang presisi. Kita tidak punya waktu untuk melakukan refactor kode secara menyeluruh malam itu juga. Yang kita butuhkan adalah menghentikan pendarahan resource di server.

Berikut adalah rangkaian perintah darurat (Emergency Runbook) one-liner terminal yang langsung saya eksekusi untuk menyelamatkan sistem dalam waktu kurang dari 60 detik:

# 1. Hentikan sementara seluruh worker agar tidak memperparah beban database
sudo supervisorctl stop all

# 2. Flush antrean yang rusak parah di Redis untuk menyelamatkan RAM (Opsional/Darurat)
redis-cli -h 127.0.0.1 -p 6379 eval "return redis.call('del', unpack(redis.call('keys', 'queues:ProcessBulkOrders*')))" 0

# 3. Sesuaikan ulang konfigurasi file Supervisor untuk membatasi jumlah proses worker
sudo nano /etc/supervisor/conf.d/worker.conf

Di dalam file konfigurasi Supervisor, saya melakukan penyesuaian parameter agar beban server kembali stabil dan terukur. Transisi menuju pengaturan yang lebih defensif ini menjadi fondasi agar kejadian serupa tidak terulang.

5. Kebijakan Retrospektif: Menambal Celah agar Tak Pernah Terulang

Keesokan harinya, tim melakukan blameless post-mortem. Kami merombak total cara kerja background worker berbasis Redis dan Supervisor ini. Langkah pertama adalah menulis ulang konfigurasi Supervisor agar benar-benar tangguh dan aman dijalankan di lingkungan production skala enterprise.

Berikut adalah file konfigurasi supervisord.conf yang telah dioptimalkan dengan standar production-grade:

[program:enterprise-queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --queue=high,default,low --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=8
redirect_stderr=true
stdout_logfile=/var/log/supervisor/worker.log
stopwaitsecs=3600
# Mencegah memory leak menumpuk dengan membatasi ukuran memori per proses
environment=LARAVEL_QUEUE=true

Selain itu, implementasi strategi Retry dan Dead Letter Queue (DLQ) di sisi kode aplikasi diperketat. Alih-alih menyimpan data berat, job kini hanya membawa referensi ID:

// Contoh struktur job yang ramah memori dan aman dari OOM
class ProcessBulkOrders implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 3;
    public $backoff = [60, 180, 600]; // Exponential backoff: 1m, 3m, 10m

    protected int $batchId;

    public function __construct(int $batchId)
    {
        $this->batchId = $batchId;
    }

    public function handle()
    {
        // Tarik data secara chunk langsung dari database berdasarkan ID
        Model::where('batch_id', $this->batchId)->chunk(100, function ($records) {
            // Proses data dengan aman tanpa membebani RAM
        });
    }

    public function failed(\Throwable $exception)
    {
        // Pindahkan ke Dead Letter Queue atau catat ke sistem alert khusus
        Log::critical("Job gagal secara permanen untuk Batch ID: {$this->batchId}");
    }
}

6. Pasang Alarm: Otomasi Deteksi Dini untuk Tim On-Call

Sistem yang hebat bukan berarti tidak akan pernah gagal, melainkan sistem yang tahu cara memperingatkan kita sebelum pengguna menyadarinya. Untuk memastikan alarm tengah malam tidak lagi mengejutkan, kami memasang aturan alerting baru di Prometheus dan Alertmanager.

# Contoh aturan Prometheus Alert untuk memantau antrean Redis yang menumpuk
groups:
  - name: queue_alerts
    rules:
      - alert: RedisQueueBacklogHigh
        expr: redis_list_length{queue="default\
đŸˇī¸ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server

Apakah panduan tutorial ini membantu Anda?

Masukan Anda sangat berharga untuk terus memperbarui dan menyempurnakan kualitas materi teknis kami.

🎉

Terima kasih banyak atas apresiasi Anda!

Tim kami terus menyempurnakan tutorial agar selalu akurat dengan versi teknologi terbaru.

Bantu Kami Menyempurnakan Materi Ini

⚡ Literally Tech Digest

Update Tutorial & Developer Tools Terbaru Langsung ke Email Anda

Dapatkan kurasi artikel arsitektur software, tips DevOps, panduan database, serta rilis fitur developer utility gratis setiap minggu. Bebas spam, bisa berhenti kapan saja.

âŗ Mencari artikel...
Tutorial & Artikel Terkait
Developer Tools
Tidak ditemukan tutorial atau tool dengan kata kunci "".
Ketik minimal 2 karakter untuk mencari artikel atau nama tools.
Tekan ESC untuk menutup Cari di Semua Artikel →