Worker backend yang membaca Redis Stream dari queue X mengalami timeout job secara konsisten. Langsung berangkat dari gejala dan data observasi, artikel ini menjelaskan langkah debugging untuk menemukan apakah penyebabnya adalah mis-acknowledgment, consumer lag, atau pending message, lalu memberikan perbaikan kode serta konfigurasi Redis dan worker agar timeout tersebut hilang.
Konteks Stack dan Gejala Timeout Worker Job
Tim menggunakan stack Go untuk worker, Bun sebagai ORM SQL, dan Redis Stream untuk mengatur pipeline job. Worker melakukan fetch pesan, memanggil layanan eksternal, lalu menyimpan hasilnya ke database. Timeout terjadi pada bagian pemrosesan sebelum worker berhasil XACK pesan.
Gejala yang terlihat: job berjalan hingga beberapa detik, lalu worker mengeluarkan timeout dan reconnect; job tidak dihapus dari stream sehingga selalu muncul kembali. Ini jelas menunjukkan timeout worker job yang kita telusuri.
Langkah Reproduksi Timeout
- Publikasikan 10 pesan ke Redis Stream
jobs:defaultdengan payload sederhana. - Start worker Go yang menggunakan
XREADGROUPdengan block timeout 5 detik. - Biarkan worker memproses, lalu hentikan service eksternal (misal HTTP downstream) untuk menyebabkan delay.
- Worker akhirnya memunculkan timeout dan job tetap berada di stream dengan status pending.
Langkah ini memproduksi kembali timeout dan membuat worker tidak mampu memproses job karena tidak mengeluarkan XACK.
Data Observability: Log, Trace, dan Metric
Observability menjadi kunci. Log worker menyebutkan "processing job db_insert" disusul error timeout dari HTTP client. Trace distributed menunjukkan span HTTP call menunggu 18 detik sebelum timeout, namun span Redis belum selesai karena XACK tidak terpanggil.
Metric yang diamati:
- Pending messages pada
STREAMS.PENDING jobs:defaultmenunjukkan 10 message tidak diselesaikan. - Consumer lag via
XINFO GROUPSbertambah saat worker timeout. - Retry counter di application metric naik karena job selalu diproses ulang.
Gabungan log dan metric jelas menunjuk ke kondisi di mana worker menahan stream entry tanpa menyelesaikannya.
Mendeteksi Root Cause: Mis-ack atau Consumer Lag?
Analisa root cause dimulai dengan memeriksa proses XREADGROUP. Karena worker menunggu respon HTTP, ia tidak memanggil XACK. Saat timeout, pesan tetap pending. Observasi dengan XINFO CONSUMERS menampilkan pending > 0 pada consumer yang perlu diack manual.
Cara mendeteksi:
- Gunakan
XINFO PENDING jobs:default group1untuk melihat ID message dan lama waktu pending. - Trace menunjukkan bahwa worker memegang message >
max-processing-timedan tidak merilisnya. - Jika banyak pesan pending, ini tanda consumer lag karena worker tidak menyelesaikan job.
Root cause: worker menunggu external API terlalu lama sehingga tidak mencapai XACK, menyebabkan message tetap pending dan akhirnya timeout worker job.
Perbaikan Kode, Konfigurasi Redis, dan Validasi Ulang
Perubahan Kode
Terapkan deadline context dan circuit breaker saat memanggil API eksternal:
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
defer cancel()
resp, err := httpClient.Do(req.WithContext(ctx))
if err != nil {
log.Error().Err(err).Msg("external call timeout")
return err
}
// pastikan selalu ack jika sudah selesai
if err := redisClient.XAck(ctx, stream, group, msgID).Err(); err != nil {
log.Error().Err(err).Msg("failed to ack message")
}
Pastikan XACK hanya dipanggil setelah seluruh langkah selesai sukses atau disertai mekanisme retry serta dead letter.
Penyesuaian Konfigurasi Redis dan Worker
- Redis: Set
stream-max-lengthsesuai throughput, aturmaxmemoryuntuk menghindari evictions pada stream. - Worker: Kurangi block timeout menjadi 2 detik sehingga worker sering mengecek pending, dan tetapkan
read-timeoutlebih pendek daripada overall worker timeout. - Tambahkan proses pending message reclaimer seperti goroutine untuk
XCLAIMpesan yang terlalu lama di-hold.
Validasi Ulang
Setelah perbaikan:
- Uji ulang skenario timeout dengan menurunkan kecepatan response API.
- Periksa
XINFO PENDINGuntuk memastikan angka kembali nol. - Monitor metric job success dan pastikan tidak ada penumpukan worker timeout job.
Validasi ini memastikan worker mampu menyelesaikan job atau me-release pesan agar konsumen lain dapat mengambilnya.
Kesimpulan dan Tips Debugging
Timeout worker job pada Redis Stream seringkali berasal dari penguncian XACK akibat proses downstream lama. Observabilitas, khususnya pending count dan trace waktu, membantu membedakan antara mis-ack, consumer lag, atau masalah resource.
Tips tambahan:
- Implementasikan per-message timeout sebelum melakukan heavy task.
- Gunakan
XCLAIMuntuk menanggulangi worker crash. - Selalu log ID pesan saat gagal agar mudah mencocokkan dengan
XINFO.
Pendekatan ini menjaga worker tetap responsif sekaligus mempertahankan konsistensi Redis Stream.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!