Pernah nggak kalian klik tombol "Daftar Akun" atau "Download Laporan PDF", lalu halaman loading muter terus selama 10-15 detik tanpa kepastian?
Bikin frustrasi banget, kan? Penyebabnya hampir selalu sama: server backend ngeksekusi proses berat secara sinkron (synchronous) langsung di dalam siklus request-response HTTP.
Padahal ada aturan emas di arsitektur backend modern—balikin response ke pengguna secepat mungkin, dan serahin tugas beratnya ke background worker.
Yuk, kita bahas kenapa aturan ini wajib kalian terapkan.
Poin Penting
- Background worker membebaskan siklus HTTP request-response agar API langsung merespon user dalam hitungan milidetik.
- Pola ini mencegah worker thread web server terkunci dan kehabisan kapasitas saat lonjakan trafik.
- Message broker seperti RabbitMQ atau Redis jadi penampung antrean tugas asinkron.
- Background worker independen menangani pengiriman email, generate dokumen, dan olah media.
Masalah Klasik: Request HTTP yang Menggantung
Pas seorang user ngirim request HTTP, misalnya registrasi akun baru, urutannya sering kayak gini:
- Backend bikin data user di database. (Cepat, sekitar 10 ms)
- Backend ngirim email verifikasi lewat SMTP atau API pihak ketiga. (Bisa makan 2-5 detik)
- Backend bikin avatar default dan sinkronisasi data analitik. (Bisa makan 1-3 detik)
- Baru setelah semua itu kelar, response
200 OKdikirim ke user.
Kelihatan aman-aman aja pas trafiknya sepi. Dampak aslinya baru kerasa pas lagi rame:
- User experience buruk. Pengguna nunggu lama cuma buat tahu pendaftarannya berhasil.
- Worker thread web server terkunci. Server punya batas maksimal koneksi simultan. Kalau koneksi tertahan lama buat urusan kirim email, server bisa kehabisan kapasitas (thread exhaustion) dan tumbang pas ada lonjakan traffic.
Anggap kasir minimarket yang sekali ngelayanin harus ikut nungguin pelanggan ngobrol lama di dalam toko. Antrean di belakangnya makin panjang, padahal kasirnya nggak salah apa-apa. 😅
Kasir vs Koki: Cara Kerja Dapur Restoran
Biar makin kebayang, bayangin kalian mesen steak di restoran.
- Tanpa background worker: kasir nyatet pesanan, lalu si kasir sendiri masuk ke dapur, nyalain kompor, manggang daging 20 menit, naruhnya di piring, baru ngasih struk ke kalian. Antrean di kasir mengular panjang karena kasir sibuk masak.
- Dengan background worker: kasir nyatet pesanan, mencetak tiket ke dapur, lalu langsung ngasih struk nomor antrean ke kalian dalam hitungan detik. Koki di dapur—si worker—yang manggang daging secara terpisah. Kasir langsung bisa ngelayani pelanggan berikutnya tanpa jeda.
Prinsipnya sama persis di backend. Yang nerima pesanan jangan disuruh masak. Ibaratnya kasir nggak perlu jadi koki, kok.
Solusi: Asynchronous Task Queue & Background Worker
Dengan pendekatan asynchronous task queue, alurnya berubah jadi gini:
- Web server nerima request dan nyimpen data penting, misal ID user.
- Web server melempar instruksi tugas—contohnya "kirim email ke user ID 123"—ke dalam antrean (message queue/broker kayak Redis atau RabbitMQ).
- Web server langsung ngembaliin response
200 OK("Registrasi berhasil, silakan cek email Anda") dalam hitungan milidetik. - Di belakang layar, proses terpisah bernama background worker—misalnya Celery, RQ, atau Temporal—ngambil tugas dari antrean dan nyelesaiinnya secara mandiri.
Komponen Utama di Ekosistem Worker
- Producer (web API): aplikasi web yang nerima request dari user dan bikin tugas baru.
- Message broker / queue: tempat penampungan antrean tugas sementara, biasanya Redis atau RabbitMQ.
- Consumer / worker: skrip atau proses terpisah di server yang terus mendengarkan antrean dan ngeksekusi tugasnya.
Susunannya sederhana, sih. Tapi efeknya gede banget ke responsiveness aplikasi kalian.
Contoh Praktis di Python: FastAPI BackgroundTasks
Buat kasus sederhana yang belum butuh broker besar kayak Celery, FastAPI udah nyediain modul bawaan BackgroundTasks yang praktis banget:
import time
from fastapi import FastAPI, BackgroundTasks
app = FastAPI()
def send_welcome_email(email: str):
# Simulasi proses pengiriman email yang memakan waktu lama
time.sleep(4)
print(f"Email selamat datang berhasil dikirim ke: {email}")
@app.post("/register")
async def register_user(email: str, background_tasks: BackgroundTasks):
# 1. Simpan user ke database di sini...
# 2. Daftarkan tugas berat ke background
background_tasks.add_task(send_welcome_email, email)
# 3. Langsung kirim respon ke user tanpa menunggu email terkirim!
return {
"status": "success",
"message": "Registrasi berhasil! Email verifikasi sedang dikirim di latar belakang."
}
Dengan pola di atas, endpoint /register langsung merespon dalam hitungan milidetik, sementara pengiriman email tetap jalan aman di latar belakang.
Catatan penting nih. BackgroundTasks di FastAPI jalan di dalam proses aplikasi yang sama. Cocok buat prototipe dan tugas ringan, tapi kalau server-nya mati, tugas yang lagi jalan ikut hilang. Buat skala produksi, pindahin fungsinya ke worker service tersendiri yang mendengarkan pesan dari broker kayak RabbitMQ atau Redis.
Jadi, Kapan Mulai Pasang Background Worker?
Membebaskan siklus utama HTTP dari pekerjaan berat itu rahasia utama di balik aplikasi modern yang terasa enteng dan responsif.
Begitu aplikasi kalian mulai punya fitur kirim email verifikasi, olah gambar atau video, pembuatan dokumen laporan, atau integrasi ke layanan pihak ketiga, langsung pisahin ke background worker atau antrean terdistribusi kayak Celery. Pengguna senang karena nggak perlu nunggu lama, dan server kalian tetap kokoh pas diserbu ribuan pengunjung barengan.
Nggak perlu nunggu traffic kalian jebol dulu baru berbenah, deh. Mulai dari satu tugas berat aja.
Selamat ber-worker ria, dan semoga request kalian selalu pulang tepat waktu! 👋