# Membangun Sistem Background Job Tangguh dengan Redis dan Supervisor di VPS

> Diterbitkan oleh Literally Web ID pada 20 Oct 2026
> Sumber: https://literally.web.id/articles/membangun-sistem-background-job-tangguh-dengan-redis-dan-supervisor-di-vps

---

## 1. Alarm Tengah Malam: Saat Layanan Produksi Mulai Tumbang

Pukul 02:14 pagi, tidur saya yang lelap mendadak buyar oleh jeritan bernada tinggi dari PagerDuty. Layar ponsel saya menyala terang, memamerkan grafik metrik Prometheus yang melengkung tajam ke atas, menunjukkan penggunaan RAM pada VPS produksi yang merayap di angka 98.5%. Belum sempat saya membuka laptop untuk menyelidiki, webhook dari sistem monitoring mulai membanjiri channel Slack tim *engineering*: *"API Gateway 504 Gateway Timeout"*, *"Redis connection refused"*, dan *"Worker node unresponsive"*.

Sebagai *Principal Engineer* yang sudah belasan tahun berkubang di dunia infrastruktur web, saya tahu persis apa arti kombinasi gejala ini. Ini bukan sekadar lonjakan trafik mendadak dari pengguna. Ini adalah indikasi klasik dari bencana infrastruktur: *memory leak* masif yang menjalar ke sistem *background job*, melahap seluruh alokasi memori VPS, memicu *OOM (Out of Memory) Killer* kernel Linux, dan menyeret turun seluruh layanan esensial yang berjalan di atas mesin yang sama. Tanpa membuang detik, saya membuka terminal, mengetuk perintah `ssh root@production-vps-01`, dan bersiap menghadapi kekacauan di ruang mesin digital.

## 2. Jejak Digital: Menelusuri Anomali Log & Lonjakan Metrik

Begitu masuk ke dalam mesin, saya langsung meluncurkan `htop` untuk melihat proses apa yang sedang mencekik leher server. Hasilnya langsung menampar muka saya: puluhan proses PHP-CLI dan Node.js berjalan liar, masing-masing memakan 3% hingga 7% RAM. Padahal, secara arsitektur, tugas-tugas latar belakang ini seharusnya dikelola dengan rapi menggunakan Supervisor agar jumlah prosesnya terbatasi. Namun, yang terjadi di lapangan jauh dari kata rapi.

> [!WARNING]
> Ketika proses *background job* dibiarkan berjalan tanpa batas konkurensi (*concurrency limit*) dan penanganan memori yang buruk di dalam ekosistem VPS, mereka akan bertindak seperti parasit yang menyedot habis sumber daya sistem hingga layanan web utama ikut lumpuh.

Saya beralih memeriksa log Supervisor dengan perintah `tail -n 100 /var/log/supervisor/worker-err.log`. Baris demi baris log berteriak memunculkan pesan error yang sama: `Allowed memory size of 536870912 bytes exhausted`. Ternyata, aplikasi yang memproses laporan PDF berukuran besar di latar belakang mengumpulkan seluruh data di dalam memori tanpa pernah melakukan *garbage collection* atau pembersihan variabel secara berkala. Ketika tugas tersebut selesai, memori tidak dikembalikan sepenuhnya ke sistem operasi, menciptakan *fragmentasi memori* yang lambat laun membuat proses tersebut membengkak hingga puluhan gigabyte.

Tidak berhenti di situ, saya juga memeriksa log Redis melalui `redis-cli monitor`. Di sana, terlihat jutaan perintah `BLPOP` yang menumpuk karena worker yang seharusnya memproses antrean tersebut mendadak mati akibat dibunuh oleh kernel Linux karena kehabisan RAM. Antrean di dalam Redis meluber, memakan sisa memori cache yang ada, dan menciptakan efek domino kegagalan sistemik yang merontokkan seluruh infrastruktur backend web dalam hitungan menit.

## 3. Membongkar Biang Kerok: Akar Masalah yang Sebenarnya

Setelah berhasil menjinakkan server yang hampir lumpuh total dengan merestart layanan terkait, saya duduk kembali untuk melakukan bedah bangkai (*post-mortem*) secara mendalam. Mengapa sistem yang tadinya berjalan stabil bisa berubah menjadi mimpi buruk di tengah malam? Ada tiga dosa besar arsitektural yang kami temukan:

1. **Konfigurasi Supervisor yang Terlalu Longgar**: File konfigurasi Supervisor kami mendefinisikan `numprocs=8` tanpa batasan daur hidup proses (`maxrequests`). Artinya, proses worker tersebut akan terus hidup selamanya di latar belakang, memproses ribuan *job* secara beruntun tanpa pernah melepaskan memori yang terakumulasi.
2. **Absennya *Graceful Shutdown* di Level Aplikasi**: Ketika Supervisor mencoba menghentikan atau merestart worker untuk pembaruan kode, sinyal `SIGTERM` diabaikan begitu saja oleh aplikasi karena tidak ada *signal listener* yang terpasang. Akibatnya, Supervisor terpaksa mengirimkan `SIGKILL`, yang memotong proses di tengah jalan dan meninggalkan data korup di dalam database serta koneksi database yang menggantung (*orphan connections*).
3. **Manajemen Redis Queue Tanpa Visibilitas**: Kami mengandalkan Redis sebagai *message broker* tanpa memantau ukuran antrean secara *real-time*. Ketika worker melambat karena memori bengkak, Redis terus menerima *payload* baru hingga menghabiskan sisa RAM yang ada di server.

> [!TIP]
> Selalu terapkan pola *ephemeral worker* dalam arsitektur *background job*. Biarkan worker mati dan digantikan oleh proses baru secara otomatis setelah menyelesaikan sejumlah tugas tertentu untuk memastikan tidak ada sisa memori yang tertinggal.

## 4. Tindakan Darurat: Menghidupkan Kembali Layanan dalam Hitungan Menit

Untuk memastikan sistem tidak kembali tumbang saat jam kerja dimulai beberapa jam lagi, saya harus merombak konfigurasi infrastruktur saat itu juga. Langkah pertama adalah memperbarui file konfigurasi Supervisor agar lebih tahan banting terhadap *memory leak*.

Berikut adalah konfigurasi baru `/etc/supervisor/conf.d/worker-app.conf` yang langsung saya terapkan ke server:

```ini
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --queue=default,emails,reports --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/log/supervisor/worker.log
stopwaitsecs=3600

; Pengaman utama untuk mencegah memory leak menumpuk
stopevent=TERM
```

Untuk memastikan proses benar-benar mendaur ulang dirinya sendiri sebelum memori membengkak, saya menambahkan skrip di level kode aplikasi yang membatasi jumlah eksekusi per proses sebelum akhirnya melakukan *restart* mandiri:

```php
// Di dalam file Worker Command kustom aplikasi
public function handle()
{
    $maxJobs = 500;
    $currentJobs = 0;

    while (true) {
        $job = Redis::pop('default');
        if (!$job) {
            sleep(1);
            continue;
        }

        // Eksekusi tugas latar belakang
        $this->processJob($job);
        $currentJobs++;

        // Paksa keluar jika sudah mencapai batas aman untuk didaur ulang Supervisor
        if ($currentJobs >= $maxJobs) {
            Log::info('Worker mencapai batas maksimum job, melakukan restart damai...');
            exit(0);
        }
    }
}
```

Setelah file konfigurasi diperbarui, saya langsung mengeksekusi perintah darurat berikut di terminal VPS untuk memuat ulang Supervisor:

```bash
sudo supervisorctl reread && sudo supervisorctl update && sudo supervisorctl restart all
```

Dalam waktu kurang dari 60 detik, grafik penggunaan RAM langsung terjun bebas ke angka normal 32%, dan antrean di Redis kembali bersih tanpa ada satupun *request* yang terbuang.

## 5. Kebijakan Retrospektif: Menambal Celah agar Tak Pernah Terulang

Insiden pukul 02:14 pagi ini memberikan pelajaran mahal bagi tim kami. Agar tragedi serupa tidak terulang di masa mendatang, kami menetapkan beberapa kebijakan arsitektural baru yang wajib dipatuhi oleh seluruh engineer:

- **Pemisahan Sumber Daya (Resource Isolation)**: Ke depannya, VPS yang menjalankan Redis dan *background worker* berintensitas tinggi harus dipisahkan dari server web utama (Nginx/PHP-FPM) atau setidaknya diberikan *cgroups memory limit* yang ketat agar tidak bisa mencaplok memori sistem operasi.
- **Implementasi *Graceful Shutdown* Menyeluruh**: Setiap skrip worker di level bahasa pemrograman wajib mendengarkan sinyal `SIGTERM` dan `SIGINT`. Ketika sinyal diterima, worker harus menyelesaikan *job* yang sedang berjalan saat itu, menutup koneksi database dengan aman, baru kemudian menutup diri.
- **Uji Coba Bebas Kebocoran (*Stress Testing*)**: Sebelum sebuah fitur baru yang melibatkan pemrosesan data besar dilempar ke lingkungan produksi, tim QA wajib menjalankan skenario *load testing* menggunakan `k6` atau `Apache JMeter` khusus untuk memantau perilaku memori worker selama 24 jam non-stop.

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

Kami tidak ingin lagi bergantung pada keluhan pengguna atau kebetulan semata untuk mengetahui kapan server sekarat. Oleh karena itu, kami merombak sistem pemantauan dengan memasang aturan *alerting* otomatis yang terintegrasi langsung dengan webhook Slack dan PagerDuty.

Berikut adalah cuplikan konfigurasi Prometheus *Alertmanager* (`alert.rules.yml`) yang kami pasang untuk mendeteksi dini lonjakan memori pada proses Supervisor sebelum insiden benar-benar terjadi:

```yaml
groups:
- name: WorkerNodeAlerts
  rules:
  - alert: HighMemoryConsumption
    expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes > 0.85
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "Penggunaan RAM VPS kritis di atas 85%"
      description: "Host {{ $labels.instance }} mengalami kebocoran memori atau lonjakan antrean Redis yang tidak wajar. Segera cek Supervisor!"

  - alert: RedisQueueBacklog
    expr: redis_list_length{key="queue:default"} > 5000
    for: 2m
    labels:
      severity: warning
    annotations:
      summary: "Antrean Redis menumpuk lebih dari 5000 job"
      description: "Worker kemungkinan besar mati atau lambat memproses data di antrean default."

```

Dengan sistem *early warning system* yang presisi ini, jika suatu hari *memory leak* kembali mencoba merayap naik di tengah malam, tim on-call akan mendapatkan notifikasi jauh sebelum server sempat berteriak minta tolong. Arsitektur yang tangguh bukanlah arsitektur yang tidak pernah gagal, melainkan arsitektur yang tahu bagaimana cara bangkit dengan cepat dan belajar dari setiap kejatuhannya.