Consumer queue sering memerlukan waktu untuk menyelesaikan pekerjaan sebelum pesan aman untuk di-acknowledge. Menghapus pesan saat diterima membuat crash pada consumer berpotensi menghilangkan pekerjaan. Membiarkannya langsung tersedia membuat beberapa consumer dapat memproses item yang sama secara bersamaan.

Visibility timeout mengambil posisi di antara kedua pilihan tersebut. Saat pesan diterima, pesan menjadi tidak tersedia sementara bagi consumer lain. Consumer memperoleh interval terbatas untuk menyelesaikan pekerjaan dan mengirim acknowledgement. Jika interval habis lebih dahulu, queue dapat membuka pesan untuk delivery berikutnya.

Kontrak ini lebih tepat dipandang sebagai lease daripada kepemilikan. Delivery memberi hak pemrosesan sementara; acknowledgement menyelesaikan handoff.

Receive mengubah eligibility, bukan keberadaan durable

Bayangkan queue berisi satu pesan yang siap diproses:

t0  pesan ready
t1  consumer A menerima pesan
t2  pesan invisible sampai t1 + 30s
t3  consumer A mengirim acknowledgement
t4  pesan dikeluarkan dari delivery normal

Di antara t1 dan t3, pesan tetap penting bagi queue walaupun consumer lain biasanya tidak dapat menerimanya. Visibility state dan durable message state adalah dua konsep terpisah.

Jika consumer A berhenti pada t2 tanpa acknowledgement, queue tidak memerlukan pesan recovery dari proses tersebut. Setelah lease kedaluwarsa, pesan asli kembali eligible.

t0  ready
t1  dikirim ke A; invisible selama 30s
t2  A crash
t31 lease kedaluwarsa
t32 dikirim ke B

Jalur recovery ini menghilangkan ketergantungan permanen pada kesehatan consumer yang pertama menerima pekerjaan.

Timeout menjadi bagian dari semantik pemrosesan

Visibility timeout yang lebih pendek daripada durasi pemrosesan normal menimbulkan concurrent delivery yang sebenarnya dapat dihindari. Misalnya sebuah job biasanya memerlukan 45 detik, sedangkan interval visibility hanya 30 detik. Pada detik ke-30, consumer lain dapat menerima pesan yang sama ketika consumer pertama masih bekerja.

Timeout yang terlalu panjang membawa biaya sebaliknya. Saat consumer benar-benar berhenti, pekerjaan retry tetap tersembunyi sampai lease kedaluwarsa.

Interval tersebut menjadi pertukaran antara redelivery prematur dan latency recovery. Nilai tetap cocok ketika durasi pemrosesan memiliki batas yang jelas dan relatif stabil. Workload dengan durasi bervariasi sering memerlukan perpanjangan lease.

receive(message, visibility=30s)

while processing:
    if lease_near_expiry:
        extend_visibility(message, 30s)

ack(message)

Perpanjangan sebaiknya terkait progres nyata atau policy yang memiliki batas. Lease yang terus diperpanjang tanpa batas dapat membuat consumer macet menekan mekanisme recovery tanpa akhir.

Acknowledgement perlu mengidentifikasi delivery attempt

Satu pesan dapat dikirim lebih dari sekali sepanjang masa hidupnya. API queue umumnya mengembalikan receipt, delivery token, atau handle serupa untuk operasi receive saat ini. Acknowledgement sebaiknya memakai nilai khusus attempt tersebut, bukan menganggap stable message ID sebagai otoritas yang cukup.

Perbedaan ini penting setelah lease kedaluwarsa. Consumer A mungkin masih menyimpan state lokal yang usang ketika consumer B sudah menerima attempt yang lebih baru. Acknowledgement dari A tidak boleh secara tidak sengaja menyelesaikan delivery aktif milik B.

message id:      job-42

attempt A:
  receipt: r1
  lease:   expired

attempt B:
  receipt: r2
  lease:   active

Receipt per attempt memungkinkan queue menolak atau mengabaikan completion usang sesuai kontrak API. Stable message ID tetap berguna untuk deduplication pada level aplikasi, tracing, dan identitas bisnis, tetapi fungsinya berbeda.

Redelivery membuat idempotency menjadi tanggung jawab aplikasi

Visibility lease mengurangi risiko pesan hilang setelah consumer gagal, tetapi tidak membuat side effect terjadi exactly once.

Consumer dapat menyelesaikan side effect eksternal lalu gagal sebelum acknowledgement diterima queue:

1. operasi debit commit
2. consumer mengirim acknowledgement
3. koneksi gagal sebelum acknowledgement diterima
4. visibility lease kedaluwarsa
5. pesan dikirim lagi

Delivery kedua tidak dapat menyimpulkan dari state queue bahwa debit sudah commit. Aplikasi memerlukan idempotency boundary untuk effect yang tidak boleh terulang.

Salah satu desain menyimpan stable operation key bersama mutasi bisnis lalu menolak commit kedua dengan key yang sama. Desain lain mencatat message ID yang sudah diproses dalam transaksi yang sama dengan perubahan state lokal. Boundary yang tepat bergantung pada resource yang diubah; acknowledgement queue tidak dapat membuat database terpisah atau remote API menjadi atomik.

Renewal memerlukan failure policy

Perpanjangan lease berguna untuk job panjang, tetapi proses renewal juga dapat gagal. Network partition, queue service yang overload, credential kedaluwarsa, atau process stall dapat membuat extension tidak tiba sebelum deadline saat ini.

Consumer sebaiknya memperlakukan lease expiry sebagai hilangnya hak pemrosesan eksklusif. Melanjutkan side effect yang irreversible setelah consumer tidak lagi dapat memastikan lease masih valid dapat berpacu dengan consumer pengganti.

Sebagian workload dapat berhenti dengan aman ketika lease hilang. Workload lain memerlukan fencing mechanism pada level aplikasi, version check, atau conditional write pada resource yang sedang diubah. Queue lease sendiri tidak dapat memagari write ke sistem eksternal yang tidak ikut dalam lease protocol.

Frekuensi renewal juga memerlukan margin. Meminta extension tepat pada batas expiry tidak menyisakan ruang bagi network delay dan scheduling delay. Implementasi biasanya melakukan renewal lebih awal dan menyediakan slack yang cukup untuk latency sementara tanpa membuat traffic renewal menjadi loop yang rapat.

Retry counter dan dead-letter policy berada di atas visibility

Lease expiry yang berulang dapat menandakan poison message, error aplikasi deterministik, atau worker yang tidak mampu selesai dalam alokasi waktunya. Redelivery tanpa batas dapat menghabiskan kapasitas tanpa menghasilkan progres.

Queue sering menyediakan delivery count atau redrive policy yang memindahkan pesan yang berulang kali gagal ke dead-letter queue setelah threshold tertentu. Policy ini terpisah dari visibility timer:

receive
  |
  +-- sukses -> acknowledge
  |
  `-- tanpa acknowledgement
          |
          v
     visibility expires
          |
          v
     delivery count + 1
          |
      +---+---+
      |       |
    retry   dead-letter

Threshold perlu mencerminkan tujuan operasional. Gangguan dependency sementara dapat layak mendapat retry, sedangkan input malformed dapat gagal dengan cara yang sama pada setiap attempt. Backoff dapat mencegah failure berulang langsung mengambil kembali kapasitas consumer.

Observability perlu memperlihatkan tekanan pada lease

Queue depth saja tidak menunjukkan apakah consumer hampir kehilangan lease. Signal yang berguna mencakup usia pesan ready tertua, jumlah pesan in-flight, durasi pemrosesan, jumlah lease extension, jumlah redelivery, acknowledgement failure, dan volume dead-letter.

Kenaikan extension count dapat menandakan timeout awal sudah tidak sesuai dengan durasi pemrosesan. Redelivery yang meningkat sementara business effect berhasil dapat mengarah pada acknowledgement failure atau idempotency yang belum memadai. Usia pesan ready yang terus naik menunjukkan throughput consumer yang tersedia tertinggal dari arrival rate.

Tracing per pesan juga lebih jelas ketika log membedakan message identity dari delivery-attempt identity. Trace dapat menunjukkan bahwa job-42 diproses di bawah r1, kedaluwarsa, lalu selesai di bawah r2 tanpa memperlakukan kedua attempt sebagai business job yang berbeda.

Lease boundary menjaga failure tetap dapat dipulihkan

Visibility timeout tidak menjanjikan single delivery. Mekanisme ini membuat satu delivery attempt tersembunyi dari consumer lain selama interval terbatas, lalu menyediakan jalur deterministik agar pesan kembali eligible ketika completion tidak terjadi.

Boundary tersebut memberi queue failure model yang praktis. Consumer dapat menghilang tanpa memiliki pekerjaan secara permanen, job lambat dapat memperpanjang lease, attempt usang dapat dipisahkan dari attempt aktif, dan duplicate effect dapat dikendalikan pada application boundary tempat effect tersebut benar-benar terjadi.