Worker, Queue, dan Cron Job untuk Aplikasi Produksi yang Stabil

Engineering 10 Jul 2026 · OTPZap Team

Banyak aplikasi web terlihat sederhana dari luar: user klik tombol, data tersimpan, status berubah. Tetapi di belakang layar, aplikasi produksi yang stabil hampir selalu punya pekerjaan latar belakang. Ada email yang harus dikirim, pembayaran yang harus dicek, order yang harus dipantau, cache yang harus disegarkan, file yang harus diproses, dan notifikasi yang harus dikirim tanpa membuat request user menjadi lambat.

Di sinilah worker, queue, dan cron job menjadi penting. Tanpa desain yang benar, pekerjaan latar belakang bisa menjadi sumber bug paling mahal: proses jalan dua kali, refund dobel, email terkirim berulang, status order nyangkut, atau job hilang saat server restart. Artikel ini membahas cara mendesain background processing yang realistis untuk aplikasi web produksi.

Apa bedanya worker, queue, dan cron?

Cron job adalah jadwal. Ia menjalankan perintah pada interval tertentu, misalnya setiap menit, setiap lima menit, atau setiap malam. Queue adalah antrian pekerjaan. Aplikasi memasukkan job ke antrian, lalu worker mengambil dan mengerjakannya. Worker adalah proses yang menjalankan job tersebut.

Contoh sederhana: saat user daftar, aplikasi tidak perlu mengirim email di request utama. Aplikasi cukup memasukkan job kirim email ke queue. Worker mengambil job itu dan mengirim email. Jika gagal, worker bisa retry tanpa user harus menunggu.

Kapan cukup cron, kapan perlu queue?

Cron cukup untuk pekerjaan berkala yang sederhana: membersihkan session lama, mengecek deposit pending, membuat laporan harian, atau menghapus cache expired. Queue lebih cocok untuk pekerjaan per event: kirim email setelah registrasi, proses upload file, sinkronisasi data order, atau mengirim notifikasi per user.

Jika pekerjaan bisa menumpuk dan butuh retry per item, gunakan queue. Jika pekerjaan hanya perlu dijalankan berkala dan bisa memindai database, cron masih masuk akal.

Masalah klasik background job

1. Job berjalan dua kali

Ini bisa terjadi jika cron overlap, worker restart saat job belum selesai, atau ada dua server menjalankan perintah yang sama. Solusinya adalah locking dan idempotency. Lock mencegah dua proses mengerjakan resource yang sama. Idempotency memastikan jika job terulang, hasilnya tetap aman.

2. Job gagal diam-diam

Worker yang mati tanpa alert bisa membuat order, email, atau sinkronisasi berhenti. Setiap worker penting harus punya health check, log error, dan alert jika tidak memproses job dalam waktu tertentu.

3. Retry membuat efek samping berulang

Retry itu wajib, tetapi berbahaya jika efek samping tidak aman. Jika job kirim notifikasi retry tiga kali, user bisa menerima tiga notifikasi. Jika job refund retry tanpa guard, saldo bisa bertambah lebih dari sekali. Karena itu setiap job yang mengubah data harus punya kunci unik.

Prinsip desain worker yang aman

Locking: sederhana tapi krusial

Lock bisa dibuat di database, Redis, atau file lock, tergantung arsitektur. Untuk aplikasi kecil, database lock sering cukup. Contohnya, saat worker mengambil satu order untuk diproses, update status dari pending ke processing dengan syarat status masih pending. Jika update affected row nol, berarti proses lain sudah mengambilnya.

Jangan mengambil data dengan SELECT lalu menganggap kamu satu-satunya proses. Di produksi, dua worker bisa membaca data yang sama dalam milidetik yang berdekatan. Gunakan update bersyarat atau lock eksplisit.

Idempotency pada job

Idempotency berarti aksi bisa diulang tetapi hasil akhirnya sama. Misalnya job settlement refund memakai key REFUND-order123. Sebelum menambah saldo, sistem cek apakah key itu sudah pernah dipakai. Jika sudah, job dianggap selesai tanpa menambah saldo lagi.

Ini penting untuk semua job yang punya efek samping: refund, charge, kirim email penting, generate invoice, atau update status terminal.

Retry yang sehat

Jangan retry setiap detik selamanya. Gunakan exponential backoff: retry setelah 10 detik, 30 detik, 2 menit, 10 menit, lalu masuk failed jika tetap gagal. Simpan error terakhir agar engineer bisa membaca penyebabnya. Untuk error permanen, seperti input tidak valid, jangan retry terlalu banyak.

Cron overlap

Cron yang berjalan setiap menit bisa overlap jika satu eksekusi memakan waktu lebih dari satu menit. Gunakan lock global per command. Jika lock masih aktif, eksekusi berikutnya keluar dengan aman. Pastikan lock punya TTL agar tidak terkunci selamanya jika proses mati.

Monitoring minimal

Metric sederhana ini sering lebih berguna daripada dashboard rumit. Jika job pending naik terus, worker kurang cepat atau ada error. Jika umur job tertua terlalu lama, user akan merasakan delay.

Checklist sebelum production

  1. Matikan worker di staging saat job berjalan, lalu hidupkan lagi. Pastikan job tidak hilang.
  2. Jalankan dua worker sekaligus. Pastikan tidak ada double process.
  3. Paksa API eksternal timeout. Pastikan retry aman.
  4. Uji cron overlap. Pastikan lock bekerja.
  5. Uji deploy/restart. Pastikan worker kembali aktif.
  6. Cek log. Pastikan error bisa dipahami manusia.

Pola yang cocok untuk aplikasi kecil

Untuk aplikasi kecil, kamu tidak harus langsung memakai sistem queue kompleks. Database table sebagai queue, cron per menit, dan worker command bisa cukup jika didesain rapi. Yang penting bukan teknologi paling mahal, tetapi jaminan bahwa job tidak hilang, tidak dobel, dan bisa diaudit.

Kesimpulan

Worker, queue, dan cron job adalah fondasi aplikasi produksi yang stabil. Mereka membuat request user cepat, pekerjaan berat berjalan di belakang layar, dan sistem tetap bisa pulih dari timeout atau restart. Tetapi background job harus dirancang dengan lock, idempotency, retry, dan monitoring. Tanpa itu, proses latar belakang mudah berubah menjadi sumber bug yang sulit dilacak.

Untuk produk digital seperti dashboard, sistem pembayaran, notifikasi, atau layanan berbasis API, background processing yang rapi bukan fitur tambahan. Ia adalah bagian dari reliability utama.