Runbook queue manual dibutuhkan saat sistem background processing mulai bermasalah: job macet, retry storm, duplicate processing, cache stale, atau lock orphan. Pada situasi seperti ini, tim tidak bisa hanya mengandalkan intuisi, dashboard yang samar, atau saran AI yang terdengar meyakinkan tetapi tidak memahami konteks arsitektur Anda.

Belakangan ini muncul kekhawatiran tentang penurunan ketajaman skill teknis ketika engineer terlalu cepat menyerahkan diagnosis ke alat bantu otomatis. Konteks itu relevan, tetapi solusi praktisnya bukan menolak otomatisasi. Solusinya adalah memiliki runbook operasional yang manual, eksplisit, dan dapat dieksekusi, sehingga saat insiden terjadi, tim tahu urutan berpikir, titik cek, dan keputusan aman yang harus diambil.

Artikel ini fokus pada praktik engineering: gejala umum pada queue dan worker, langkah diagnosis berurutan, metrik serta log minimum yang wajib tersedia, kapan harus pause worker atau drain queue, checklist mitigasi cepat, verifikasi pascaperbaikan, dan template runbook yang bisa langsung dipakai.

Mengapa runbook queue manual tetap penting

Pada banyak sistem backend, queue memegang pekerjaan yang tidak boleh gagal diam-diam: pengiriman email, sinkronisasi pembayaran, indexing, pembuatan invoice, webhook outbound, komputasi laporan, hingga update cache. Ketika worker atau cache bermasalah, efeknya sering tidak langsung terlihat di halaman utama aplikasi, tetapi dampaknya nyata:

  • Data terlambat konsisten: status order sudah dibayar, tetapi invoice belum terbit.
  • Pemrosesan ganda: callback diproses dua kali karena retry tanpa idempotency.
  • Ledakan beban: worker gagal, retry meningkat, lalu database dan Redis ikut tertekan.
  • Incident berantai: cache stale membuat worker salah mengambil keputusan, lalu lock orphan menahan job lain.

Runbook manual penting karena ia memaksa tim menjawab pertanyaan yang sering diabaikan alat otomatis:

  • Apa gejala awal dan komponen pertama yang dicurigai?
  • Apakah masalah terjadi di producer, broker, worker, cache, lock, atau downstream service?
  • Aman atau tidak jika worker dihentikan sementara?
  • Job mana yang boleh di-retry, mana yang harus dikarantina?
  • Bagaimana memastikan consistency setelah perbaikan?

Prinsip utama: otomatisasi mempercepat eksekusi, tetapi runbook manual menjaga kualitas keputusan. Tanpa pemahaman manual, tim cenderung menekan tombol restart, scale up, atau requeue massal tanpa tahu konsekuensinya.

Gejala umum pada sistem queue, cache, worker, dan locking

1. Job macet atau backlog terus naik

Gejalanya biasanya terlihat dari antrean yang menumpuk, latency job meningkat, atau SLA background task terlewati.

Penyebab umum:

  • Worker mati atau tidak mengambil job baru.
  • Concurrency terlalu rendah dibanding laju producer.
  • Downstream lambat, misalnya database, API eksternal, atau storage.
  • Job tertentu deadlock atau timeout lalu menyumbat worker pool.

2. Duplicate processing

Order diproses dua kali, webhook dikirim ulang, saldo terpotong lebih dari sekali, atau record idempotency tidak dihormati.

Penyebab umum:

  • Retry terjadi setelah timeout padahal proses pertama sebenarnya selesai.
  • Visibility timeout atau acknowledgement tidak sinkron dengan durasi job.
  • Idempotency key tidak ada atau implementasinya lemah.
  • Worker crash setelah efek samping terjadi tetapi sebelum status sukses tersimpan.

3. Cache stale atau tidak konsisten

Frontend atau service lain membaca data lama meskipun database sudah berubah. Pada sistem yang heavily cached, ini sering disalahartikan sebagai bug bisnis padahal akar masalahnya invalidation.

Penyebab umum:

  • Job invalidasi cache gagal atau tertunda.
  • TTL terlalu panjang untuk data yang sering berubah.
  • Write-through atau write-behind tidak konsisten.
  • Namespace key tidak jelas sehingga pembersihan parsial gagal.

4. Lock orphan

Lock tertinggal karena worker mati mendadak, proses hang, atau cleanup tidak berjalan. Akibatnya job lain mengira resource masih dipakai dan berhenti memproses.

Penyebab umum:

  • Lock tidak memiliki expiry yang masuk akal.
  • Expiry ada, tetapi lebih panjang daripada kebutuhan operasional.
  • Release lock tidak dijalankan pada semua jalur error.
  • Identitas pemilik lock tidak tercatat sehingga sulit dibedakan lock valid vs lock orphan.

5. Retry storm

Ini salah satu mode kegagalan paling mahal. Job gagal dalam jumlah besar, di-retry otomatis, lalu menekan broker, cache, database, dan downstream sekaligus.

Penyebab umum:

  • Dependency eksternal sedang down atau rate limited.
  • Bug deployment menyebabkan semua job tipe tertentu gagal seragam.
  • Backoff terlalu agresif atau nyaris tidak ada.
  • Poison message terus berputar tanpa dipindah ke dead-letter queue atau quarantine.

Urutan diagnosis yang aman dan konsisten

Runbook yang baik tidak dimulai dari restart acak. Mulailah dari pertanyaan: apakah sistem tidak memproses, memproses lambat, atau memproses salah? Tiga kondisi ini menghasilkan tindakan berbeda.

Langkah 1: Tetapkan radius insiden

  • Layanan apa yang terdampak: email, pembayaran, notifikasi, sinkronisasi inventori?
  • Mulai sejak kapan?
  • Apakah semua queue terdampak atau hanya queue tertentu?
  • Apakah masalah hanya di satu worker group atau lintas region/cluster?

Tujuannya adalah mencegah tim langsung menyentuh semua worker padahal kerusakan hanya ada pada satu jenis job.

Langkah 2: Bedakan producer vs broker vs consumer

Periksa tiga hal ini secara terpisah:

  1. Producer: apakah aplikasi masih berhasil enqueue job?
  2. Broker/queue backend: apakah depth, age, dan throughput queue sehat?
  3. Consumer/worker: apakah worker polling, menerima, mengeksekusi, dan mengakui job dengan benar?

Banyak insiden terlihat seperti queue macet, padahal producer sebenarnya berhenti membuat job baru. Sebaliknya, backlog bisa naik bukan karena worker mati, tetapi karena producer melonjak tajam setelah event bisnis tertentu.

Langkah 3: Cek gejala level infrastruktur lebih dulu

  • CPU, memori, disk I/O, dan network pada node worker.
  • Koneksi ke broker, Redis, database, dan API eksternal.
  • Error sistem seperti OOM kill, restart container, file descriptor habis, atau DNS gagal.

Ini penting karena error aplikasi sering hanya gejala turunan dari masalah infrastruktur.

Langkah 4: Cek metrik queue inti

Metrik minimum yang perlu dilihat pada setiap insiden queue:

  • Queue depth: jumlah job menunggu.
  • Oldest job age: umur job tertua yang belum diproses.
  • In-flight/running jobs: jumlah job yang sedang diproses.
  • Success rate dan failure rate.
  • Retry rate.
  • Processing latency: waktu eksekusi job.
  • End-to-end latency: dari enqueue sampai selesai.

Jika queue depth naik tetapi in-flight rendah, kemungkinan worker tidak mengambil job. Jika in-flight tinggi tetapi throughput turun, kemungkinan worker sibuk menunggu downstream atau deadlock.

Langkah 5: Ambil contoh job nyata, jangan hanya lihat agregat

Pilih 3-5 job dari antrean yang terdampak dan telusuri:

  • Kapan dibuat?
  • Payload-nya apa?
  • Sudah berapa kali retry?
  • Worker mana yang memproses terakhir?
  • Error terakhir apa?
  • Apakah job serupa yang lebih baru ikut gagal?

Agregat membantu melihat pola, tetapi sampel job nyata membantu menemukan kelas error yang konkret.

Langkah 6: Telusuri locking dan idempotency

Jika gejalanya duplicate processing, stuck job, atau throughput mendadak turun, cek:

  • Apakah job mengambil lock?
  • Berapa TTL lock?
  • Apakah owner lock tercatat?
  • Apakah job punya idempotency key atau natural dedup key?
  • Apakah status efek samping disimpan sebelum acknowledgement?

Masalah queue sering bukan masalah antrean itu sendiri, melainkan protokol eksekusi job.

Langkah 7: Validasi dependency downstream

Pastikan database, cache, search index, object storage, payment gateway, atau API partner tidak menjadi akar masalah. Worker yang sehat tetap akan tampak rusak jika semua permintaan ke downstream timeout.

Metrik dan log yang wajib ada di runbook

Runbook hanya berguna jika observability cukup. Jika tim belum memiliki metrik dan log berikut, itu sendiri adalah temuan operasional yang perlu diperbaiki.

Metrik minimum

  • Queue depth per queue/topic.
  • Age of oldest pending job.
  • Job throughput: enqueue, dequeue, success, failure, retry per menit.
  • Worker concurrency dan worker availability.
  • Duration per jenis job, idealnya dengan persentil.
  • Dead-letter atau quarantine count.
  • Cache hit ratio untuk alur yang relevan.
  • Lock acquisition failure count dan lock wait time jika ada.

Log minimum per job

  • Job type.
  • Job ID dan correlation/request ID.
  • Entity ID bisnis, misalnya order_id atau invoice_id.
  • Attempt number.
  • Worker instance atau host/container ID.
  • Timestamps: enqueued, started, finished, failed.
  • Error class dan ringkasan penyebab.
  • Idempotency key jika digunakan.
  • Lock key jika job memakai lock.

Tanpa identitas seperti order_id, correlation ID, dan attempt number, tim akan sulit memisahkan satu insiden menjadi kasus-kasus yang bisa diuji.

Contoh format log terstruktur

{
  "event": "job_failed",
  "job_type": "send_invoice",
  "job_id": "job_8f12",
  "correlation_id": "req_a91c",
  "entity_type": "order",
  "entity_id": "ord_102938",
  "attempt": 3,
  "worker_id": "worker-queue-a-17",
  "lock_key": "lock:order:ord_102938",
  "error_class": "TimeoutError",
  "error_message": "upstream invoice service timeout",
  "enqueued_at": "2026-08-25T09:10:12Z",
  "started_at": "2026-08-25T09:13:45Z",
  "failed_at": "2026-08-25T09:14:15Z"
}

Format ini tidak tergantung framework tertentu, tetapi cukup kaya untuk diagnosis cepat.

Checklist mitigasi cepat saat insiden berjalan

Berikut checklist yang sebaiknya ada di runbook. Urutannya penting karena beberapa tindakan saling bertentangan.

1. Stabilkan sistem dulu

  • Hentikan deployment baru sampai penyebab lebih jelas.
  • Nonaktifkan fitur non-kritis yang menghasilkan banyak job jika perlu.
  • Batasi producer untuk job yang terbukti memperburuk backlog.
  • Jika ada retry storm, kurangi laju retry atau pindahkan kelas job gagal ke quarantine.

2. Lindungi downstream

  • Jika database atau API partner sudah jenuh, menambah worker belum tentu membantu.
  • Turunkan concurrency pada job yang berat.
  • Aktifkan backoff yang lebih konservatif untuk error sementara.
  • Pisahkan queue prioritas tinggi dari queue bulk jika arsitektur mendukung.

3. Cegah kerusakan data

  • Jika ada indikasi duplicate processing, hentikan sementara job dengan efek samping finansial atau eksternal.
  • Jangan melakukan requeue massal sebelum memastikan idempotency.
  • Dokumentasikan job mana yang sudah sempat menulis ke sistem lain.

4. Tangani lock orphan dengan hati-hati

  • Verifikasi apakah owner lock masih hidup.
  • Periksa umur lock dibanding durasi normal job.
  • Hapus lock manual hanya jika yakin owner sudah mati atau lock jelas melewati TTL operasional wajar.

Kesalahan umum: menghapus semua lock secara massal untuk “memulihkan” worker. Ini bisa memicu pemrosesan paralel pada resource yang seharusnya eksklusif.

Kapan pause worker, kapan drain queue

Keputusan ini harus eksplisit di runbook karena dampaknya besar.

Pause worker jika:

  • Job diketahui menghasilkan efek samping salah atau ganda.
  • Bug deployment membuat semua eksekusi tipe job tertentu pasti gagal.
  • Retry storm sedang menekan dependency dan memperluas insiden.
  • Anda perlu mencegah data corruption sambil mengumpulkan bukti.

Pause worker cocok saat melanjutkan pemrosesan lebih berbahaya daripada menambah backlog.

Drain queue jika:

  • Worker sehat, tetapi backlog perlu dikurangi terkontrol.
  • Dependency sudah pulih dan Anda ingin memproses antrean lama dengan laju terbatas.
  • Anda perlu mengosongkan queue sebelum cutover, maintenance, atau migrasi konsumen.

Drain queue berarti memproses antrean sampai habis atau sampai target tertentu, biasanya dengan concurrency yang diawasi ketat, bukan menghentikan sistem total.

Jangan pause semua worker secara membabi buta jika:

  • Hanya satu queue yang rusak.
  • Ada job prioritas tinggi yang masih aman diproses.
  • Sistem Anda menggunakan queue yang berbagi broker tetapi berbeda blast radius.

Prinsipnya: isolasi kerusakan semaksimal mungkin.

Skenario backend produksi: order dibayar, invoice dan email tertunda

Misalkan sistem e-commerce memiliki alur seperti ini:

  1. API pembayaran menandai order sebagai paid di database.
  2. Aplikasi mengirim job generate_invoice.
  3. Setelah invoice sukses, worker mengirim job send_invoice_email.
  4. Cache detail order di-refresh agar dashboard admin menampilkan status terbaru.

Insiden terjadi: order sudah dibayar, tetapi invoice tidak muncul, email tidak terkirim, dan dashboard admin masih menampilkan status lama.

Diagnosis singkat

  • Queue generate_invoice backlog naik tajam.
  • Retry rate meningkat.
  • Log menunjukkan timeout ke invoice service.
  • Worker masih hidup, tetapi duration job membengkak.
  • Cache invalidation juga tertahan karena dijalankan setelah invoice step.

Keputusan operasional

  • Pause sementara queue generate_invoice jika timeout memicu duplicate invoice atau penagihan eksternal.
  • Biarkan queue lain yang tidak terkait tetap berjalan.
  • Kurangi retry agresif, pindahkan job yang gagal berulang ke quarantine.
  • Validasi apakah invoice service sedang lambat atau ada perubahan deployment.

Setelah akar masalah ditemukan

Misalnya akar masalah adalah koneksi invoice service yang timeout karena pool koneksi salah konfigurasi. Setelah diperbaiki:

  • Nyalakan kembali worker untuk queue terkait dengan concurrency rendah lebih dulu.
  • Ambil sampel job lama dan pastikan idempotency invoice aman.
  • Drain backlog bertahap.
  • Verifikasi cache order kembali segar setelah pipeline pulih.

Contoh ini menunjukkan bahwa queue, cache, dan consistency tidak bisa diperlakukan sebagai komponen terpisah. Keterlambatan satu job bisa muncul sebagai data stale di tempat lain.

Trade-off otomatisasi vs pemahaman manual

Otomatisasi tetap penting: auto-scaling worker, dead-letter routing, retry policy, health check, dan alerting adalah praktik baik. Tetapi semuanya punya trade-off.

Di mana otomatisasi membantu

  • Menangani lonjakan beban yang memang normal.
  • Memindahkan poison message setelah ambang retry tertentu.
  • Menjalankan restart terbatas untuk proses yang crash sesekali.
  • Memberi alert lebih awal berdasarkan backlog dan latency.

Di mana pemahaman manual tetap wajib

  • Menilai apakah retry aman secara bisnis.
  • Menentukan apakah lock boleh dihapus.
  • Membedakan bug idempotency vs timeout downstream.
  • Memutuskan apakah queue harus di-pause sebagian atau total.
  • Melakukan rekonsiliasi data pascainsiden.

Masalahnya bukan otomatisasi itu sendiri, melainkan ketika tim kehilangan model mental tentang bagaimana job berpindah dari producer ke broker, lalu ke worker, lalu ke efek samping bisnis. Runbook manual menjaga model mental itu tetap hidup.

Verifikasi pascaperbaikan: jangan berhenti saat grafik turun

Insiden queue belum selesai hanya karena backlog menurun. Verifikasi pascaperbaikan harus memeriksa correctness, bukan hanya throughput.

Checklist verifikasi

  1. Backlog turun secara stabil, bukan hanya sesaat.
  2. Failure dan retry rate kembali normal.
  3. Tidak ada duplicate side effect pada sampel entity bisnis penting.
  4. Cache kembali segar pada alur yang terdampak.
  5. Lock orphan dibersihkan tanpa memicu konflik baru.
  6. Dead-letter/quarantine ditinjau untuk job yang perlu replay manual.
  7. Rekonsiliasi data dilakukan jika ada kemungkinan mismatch.

Contoh verifikasi rekonsiliasi

Untuk kasus order dan invoice, ambil sampel order dengan status paid selama rentang insiden lalu cek:

  • Apakah semua memiliki invoice?
  • Apakah hanya satu invoice per order?
  • Apakah email terkirim satu kali?
  • Apakah cache dan database menunjukkan status yang sama?

Jika sistem Anda kritikal, siapkan query atau script audit terpisah untuk rekonsiliasi seperti ini. Ini jauh lebih aman daripada mengandalkan pengamatan manual dari UI.

Template runbook queue manual yang bisa langsung dipakai

Berikut template yang dapat Anda simpan di repository operasional atau internal docs. Isi placeholder-nya sesuai sistem Anda.

Nama Runbook:
Insiden Queue / Worker / Cache / Locking

Tujuan:
Menangani job macet, duplicate processing, cache stale, lock orphan, dan retry storm
secara aman dengan menjaga consistency data.

Ruang Lingkup:
- Queue/topic yang dicakup: [...]
- Worker/service yang dicakup: [...]
- Dependency kritikal: [database, Redis, API eksternal, storage, dsb]

Gejala Pemicu:
- Backlog naik di atas [...]
- Oldest job age di atas [...]
- Failure rate job tipe [...] meningkat
- Duplicate side effect terdeteksi
- Cache stale pada endpoint/service [...]

Dashboard dan Sumber Bukti:
- Dashboard queue: [...]
- Dashboard worker: [...]
- Log query: [...]
- Tracing/correlation lookup: [...]
- Panel dependency downstream: [...]

Diagnosis Berurutan:
1. Tentukan queue/job type yang terdampak
2. Cek producer: enqueue rate normal atau tidak
3. Cek broker: depth, age, in-flight, retry
4. Cek worker: jumlah aktif, restart, error, concurrency
5. Cek downstream: DB, Redis, API eksternal
6. Ambil 3-5 sampel job dan telusuri payload + error
7. Cek idempotency, lock, TTL, dan owner lock
8. Putuskan: lanjut proses / pause sebagian / pause total / quarantine

Metrik Wajib:
- queue_depth
- oldest_job_age
- job_success_rate
- job_failure_rate
- job_retry_rate
- job_duration
- worker_active_count
- cache_hit_ratio
- lock_conflict_count

Mitigasi Cepat:
- Stop deployment baru
- Batasi producer untuk job bermasalah
- Turunkan concurrency jika downstream jenuh
- Pause queue tertentu jika ada risiko duplicate/corruption
- Pindahkan poison message ke quarantine/DLQ
- Hapus lock manual hanya setelah verifikasi owner mati

Keputusan Pause vs Drain:
- Pause jika: [...]
- Drain jika: [...]
- Queue yang tidak boleh dihentikan: [...]

Verifikasi Pascaperbaikan:
- Backlog turun stabil
- Retry kembali normal
- Sampel entity bisnis lolos cek consistency
- DLQ/quarantine direview
- Rekonsiliasi data selesai

Komunikasi Insiden:
- Incident commander: [...]
- Owner service: [...]
- Kanal komunikasi: [...]
- Update interval: [...]

Postmortem:
- Akar masalah:
- Faktor pendukung:
- Mengapa alert terlambat/cepat:
- Perbaikan jangka pendek:
- Perbaikan jangka panjang:
- Runbook yang diperbarui:

Hal yang sering terlupakan saat menyusun runbook

  • Ambang keputusan yang jelas: misalnya backlog, retry rate, atau oldest job age yang memicu eskalasi.
  • Klasifikasi job: mana yang idempotent, mana yang berisiko side effect.
  • Hubungan queue dengan cache invalidation: stale cache sering merupakan gejala sekunder dari job yang tertunda.
  • Strategi quarantine: tidak semua job gagal boleh langsung di-retry.
  • Script audit consistency: sangat membantu pascainsiden.
  • Peta dependency: worker jarang berdiri sendiri.

Penutup

Runbook queue manual bukan dokumentasi formalitas. Ia adalah alat untuk menjaga ketajaman engineering saat insiden terjadi, terutama ketika worker, cache, lock, dan consistency saling memengaruhi. Dengan runbook yang jelas, tim tidak perlu menebak-nebak atau terlalu bergantung pada AI untuk mengambil keputusan operasional yang sensitif.

Jika Anda hanya mengambil satu tindakan setelah membaca artikel ini, lakukan ini: pilih satu alur backend yang kritikal, petakan queue-nya, tentukan metrik serta log minimum, lalu tulis langkah diagnosis dan keputusan pause-versus-drain secara eksplisit. Itu sudah cukup untuk mengurangi waktu kebingungan pada insiden berikutnya.