Membangun sistem pesan asinkron dengan SQS dan SNS: membuat queue dan topic, mengirim dan menerima pesan, dead-letter queue, visibility timeout, hingga pola fan-out antar service.

Di episode 7 kita menghidupkan Lambda sebagai unit komputasi event-driven. Tapi di dunia nyata, service tidak memanggil satu sama lain secara langsung dan menunggu jawabannya — mereka bicara lewat perantara yang disebut message broker. AWS menyediakan dua service untuk ini: SQS (queue, satu konsumen per pesan) dan SNS (topic, satu pesan disiarkan ke banyak subscriber). Kalian boleh bilang: SQS itu antrian di bank, SNS itu pengeras suara masjid.
Di episode ini kalian akan membuat queue dan topic, memainkan visibility timeout dan dead-letter queue, lalu merakit pola fan-out yang menghubungkan SQS, SNS, dan Lambda dalam satu alur.
SQS adalah kandidat sempurna untuk memisahkan producer dan consumer: producer cukup drop pesan, consumer memproses sesuai kapasitasnya. Mulai dari membuat queue:
awslocal sqs create-queue --queue-name orders
awslocal sqs send-message \
--queue-url http://localhost:4566/000000000000/orders \
--message-body '{"orderId": "ORD-001"}'
awslocal sqs receive-message \
--queue-url http://localhost:4566/000000000000/ordersPerhatikan dua hal penting:
awslocal sqs delete-message dengan --receipt-handle dari hasil receive. Jika tidak di-delete, pesan akan muncul lagi.http://localhost:4566/<account>/<queue-name>. Ini alamat yang juga dipakai kode produksi saat mengakses LocalStack.Ketika sebuah consumer menerima pesan, pesan itu menjadi invisible bagi consumer lain selama periode yang disebut visibility timeout. Ini mencegah dua worker memproses pesan yang sama sekaligus. Default-nya 30 detik:
awslocal sqs create-queue --queue-name slow-orders \
--attributes VisibilityTimeout=120Jika worker gagal dan tidak menghapus pesan sebelum timeout habis, pesan kembali terlihat dan bisa dicoba worker lain. Pola ini memberi sifat at-least-once: dijamin tidak ada pesan yang hilang, tapi mungkin ada yang diproses dua kali — jadi idempotensi consumer adalah kewajiban, bukan pilihan.
Bayangkan pesan rusak yang selalu gagal diproses. Tanpa pengaman, ia akan mengotori queue selamanya dan memblokir antrian. Solusinya: dead-letter queue (DLQ), tempat sampah untuk pesan yang sudah dicoba berkali-kali tapi tetap gagal. Configurasinya lewat atribut RedrivePolicy:
awslocal sqs create-queue --queue-name orders-dlq
awslocal sqs create-queue --queue-name orders \
--attributes '{"RedrivePolicy":"{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-1:000000000000:orders-dlq\",\"maxReceiveCount\":3}"}'
awslocal sqs get-queue-attributes --queue-url http://localhost:4566/000000000000/orders \
--attribute-names AllSetelah tiga kali receive tanpa delete, pesan otomatis dipindahkan ke orders-dlq. Di sinilah kalian bisa debugging dengan tenang: ambil pesan dari DLQ, perbaiki consumer, lalu redrive kembali.
Warning
DLQ harus dibuat sebelum queue utama dirujuk di RedrivePolicy. Referensi ke ARN yang belum ada membuat pembuatan queue gagal.
SQS adalah antrian satu-ke-satu. SNS adalah pola satu-ke-banyak: satu publish menyebar ke seluruh subscriber. Buat topic, daftarkan queue SQS sebagai subscriber, lalu publish:
awslocal sns create-topic --name order-events
awslocal sns subscribe --topic-arn arn:aws:sns:us-east-1:000000000000:order-events \
--protocol sqs \
--notification-endpoint arn:aws:sqs:us-east-1:000000000000:orders
awslocal sns publish --topic-arn arn:aws:sns:us-east-1:000000000000:order-events \
--message '{"status": "paid"}'
awslocal sqs receive-message --queue-url http://localhost:4566/000000000000/ordersPola ini disebut fan-out: satu event "order dibayar" bisa sekaligus memicu pencatatan, pengiriman email, dan pembaruan inventori. Subscription bisa berupa SQS, Lambda, HTTP, maupun email (mock). Untuk email, protokol email hanya mencatat pesan ke log emulator — periksa dengan localstack logs. Untuk Lambda, arahkan --notification-endpoint ke ARN fungsi:
awslocal lambda create-function --function-name order-handler \
--runtime python3.12 --role arn:aws:iam::000000000000:role/lambda-role \
--handler handler.handler --zip-file fileb://function.zip
awslocal sns subscribe --topic-arn arn:aws:sns:us-east-1:000000000000:order-events \
--protocol lambda --notification-endpoint arn:aws:lambda:us-east-1:000000000000:function:order-handlerSaat queue perlu diproses otomatis oleh Lambda, kita pakai event source mapping seperti di episode 7. LocalStack menarik pesan dari queue dan meng-invoke fungsi dalam batch:
awslocal lambda create-event-source-mapping \
--function-name order-handler \
--event-source-arn arn:aws:sqs:us-east-1:000000000000:orders \
--batch-size 10Kombinasi ini adalah pola kerja paling umum di produksi: SNS menyiarkan event → SQS menahan beban → Lambda memproses per batch. LocalStack mendukung penuh rantai ini secara lokal.
Penting memilih jenis queue yang tepat. SQS punya dua jenis: Standard dan FIFO:
| Aspek | Standard Queue | FIFO Queue |
|---|---|---|
| Ordering | Best-effort, tidak dijamin | Ketat, per message group |
| Delivery | At-least-once (bisa duplikat) | Exactly-once dengan dedup |
| Throughput | Sangat tinggi | Terbatas, batas per group |
| Latency | Rendah | Sedikit lebih tinggi |
| Use case | Log, metrics, notifikasi | Transaksi finansial, urutan event |
Untuk urutan yang terjamin, gunakan FIFO. Namanya harus berakhiran .fifo dan setiap publish harus menyertakan --message-group-id:
awslocal sqs create-queue --queue-name orders.fifo \
--attributes FifoQueue=true,ContentBasedDeduplication=true
awslocal sqs send-message \
--queue-url http://localhost:4566/000000000000/orders.fifo \
--message-body '{"event": "created"}' --message-group-id g1Tip
Jangan asal pilih FIFO untuk semua kebutuhan. FIFO membatasi throughput dan menambah kompleksitas. Standar lebih cepat dan murah — gunakan FIFO hanya saat urutan atau duplikasi benar-benar tidak bisa ditoleransi.
Rangkuman episode ini:
create-queue, send-message, receive-message, lalu delete-message pakai receipt handle.maxReceiveCount dalam RedrivePolicy.Pesan sudah mengalir di antara service kalian. Tapi siapa yang menyajikan pesan itu ke dunia luar? Di episode 9 kita membuka pintu depan: API Gateway — REST dan HTTP API, integrasi Lambda proxy, stage, custom domain, hingga authorizer API key dan JWT. Sampai jumpa!