Amazon SQS
SQS adalah cara paling sederhana membuat sistem tahan terhadap lonjakan dan kegagalan. Untuk beban kerja LLM, ia juga rem alami terhadap rate limit.
Intisari
- Producer menaruh pesan, consumer mengambil. Keduanya tidak perlu hidup bersamaan.
- Standard: throughput hampir tak terbatas, urutan tidak dijamin, bisa terkirim lebih dari sekali. FIFO: urut dan sekali-saja, dengan batas throughput.
- Visibility timeout harus lebih besar dari waktu proses terlama — kalau tidak, pesan diproses ganda.
- Dead-letter queue menampung pesan yang gagal berkali-kali. Pasang sejak awal, bukan setelah insiden.
- Lambda + SQS: Lambda yang melakukan polling dan menghapus pesan otomatis kalau handler sukses.
Kenapa antrean, khususnya untuk LLM
Tiga masalah yang muncul begitu aplikasi GenAI-mu dipakai sungguhan, dan semuanya dijawab antrean:
| Masalah | Bagaimana antrean menjawabnya |
|---|---|
| Ingest 5.000 dokumen > 15 menit | Satu pesan per dokumen; tiap Lambda cukup mengurus satu |
Bedrock membalas ThrottlingException | Pesan kembali ke antrean dan dicoba lagi nanti, bukan hilang |
| Lonjakan trafik mendadak | Antrean menyerapnya; consumer bekerja dengan laju yang kamu kendalikan |
Standard vs FIFO
| Standard | FIFO | |
|---|---|---|
| Urutan | Usaha terbaik | Dijamin per message group |
| Pengiriman | Minimal sekali (bisa dobel) | Tepat sekali |
| Throughput | Praktis tak terbatas | Terbatas (lebih tinggi dengan batching) |
| Nama antrean | Bebas | Wajib berakhiran .fifo |
"Minimal sekali" itu bukan teori. Pada antrean Standard, handler-mu akan menerima pesan
yang sama dua kali suatu hari. Kalau handler itu memanggil Bedrock, kamu membayar token dua kali dan bisa
menyimpan hasil ganda. Rancang idempoten: turunkan kunci dari messageId atau dari isi pesan,
dan cek dulu sebelum bekerja.
Visibility timeout — sumber bug paling umum
Saat consumer mengambil pesan, pesan itu tidak dihapus; ia hanya disembunyikan selama visibility timeout. Kalau consumer selesai dan menghapusnya, tamat. Kalau tidak — pesan muncul lagi dan diproses ulang.
Ambil pesan ──▶ [tersembunyi selama N detik] ──▶ muncul lagi kalau belum dihapus
│
└─ handler selesai → pesan dihapus → selesai
Aturannya sederhana: visibility timeout > timeout fungsi consumer. Panduan umum untuk Lambda: setel sekitar enam kali timeout fungsi. Kalau terbalik, pemanggilan Bedrock yang lambat akan memicu duplikat — dan tampak seperti "bug acak yang cuma muncul saat ramai".
Menghubungkan ke Lambda
import json
def handler(event, context):
for record in event["Records"]: # bisa lebih dari satu pesan per pemanggilan
pesan = json.loads(record["body"])
proses(pesan)
# Kalau handler selesai tanpa exception, seluruh batch dihapus dari antrean.
# Kalau exception, SELURUH batch kembali — termasuk yang sudah sukses.
Komentar terakhir itu penting. Untuk menghindari mengulang pekerjaan yang sudah berhasil, aktifkan partial batch response: laporkan hanya ID yang gagal.
def handler(event, context):
gagal = []
for record in event["Records"]:
try:
proses(json.loads(record["body"]))
except Exception:
gagal.append({"itemIdentifier": record["messageId"]})
return {"batchItemFailures": gagal} # butuh ReportBatchItemFailures aktif
Dead-letter queue
Pesan yang gagal terus akan berputar selamanya dan membakar biaya. DLQ menghentikannya: setelah
maxReceiveCount percobaan, pesan dipindahkan ke antrean terpisah untuk diperiksa manusia.
Pasang DLQ pada setiap antrean produksi, dan pasang alarm CloudWatch pada
ApproximateNumberOfMessagesVisible di DLQ. Antrean DLQ yang tidak pernah dilihat sama saja
dengan tidak punya DLQ.
Latihan: buat antrean ingest-dokumen dengan DLQ (maxReceiveCount 3), hubungkan ke Lambda
yang sengaja melempar exception untuk pesan berisi {"gagal": true}. Kirim dua pesan — satu normal,
satu gagal — lalu buktikan pesan gagal berakhir di DLQ setelah tiga percobaan sementara yang normal selesai.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.