SQS & worker antrean
SQS memberi jaminan penyimpanan yang jauh lebih kuat daripada Redis, dengan imbalan beberapa batasan. Dua setelan — visibility timeout dan dead letter queue — menentukan apakah pekerjaanmu selesai atau berputar-putar diam-diam.
Intisari
- Standard queue: throughput tinggi, urutan tidak dijamin, at-least-once — job harus idempoten.
- Visibility timeout wajib lebih panjang daripada durasi job terlama, atau job diproses berkali-kali.
- Dead letter queue menangkap job yang gagal berulang — tanpa itu, ia berputar selamanya.
- Batas payload 256 KB; kirim ID, bukan data.
- Penundaan maksimum 15 menit —
delay()yang lebih panjang tidak berperilaku seperti dugaanmu.
Konfigurasi Laravel
QUEUE_CONNECTION=sqs
SQS_PREFIX=https://sqs.ap-southeast-1.amazonaws.com/123456789012
SQS_QUEUE=portal-default
AWS_DEFAULT_REGION=ap-southeast-1
// config/queue.php — tanpa key/secret; kredensial dari task role
'sqs' => [
'driver' => 'sqs',
'prefix' => env('SQS_PREFIX'),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'), // mis. "-staging"
'region' => env('AWS_DEFAULT_REGION'),
'after_commit' => true, // job hanya dikirim setelah transaksi commit
],
'after_commit' => true layak dinyalakan secara global. Ia menghapus seluruh kelas bug
"worker tidak menemukan baris yang baru dibuat" — job baru dikirim setelah transaksi benar-benar commit.
Dipasangkan dengan replication lag Aurora dari materi sebelumnya, ini menyelesaikan separuh masalah; sisanya
ditangani penundaan singkat atau membaca dari writer.
Visibility timeout — setelan yang paling sering salah
Job diambil worker
└─ pesan menjadi TIDAK TERLIHAT selama visibility timeout
├─ worker selesai → pesan dihapus ✓
└─ timeout habis sebelum selesai
└─ pesan MUNCUL LAGI → worker lain mengambilnya ✗ diproses dua kali
| Nilai | Akibat |
|---|---|
| Lebih pendek dari durasi job | Job diproses berkali-kali secara bersamaan |
| Sama dengan durasi job | Terlalu ketat; sedikit keterlambatan sudah memicu duplikat |
| 2–3× durasi job terlama | Titik awal yang benar |
| Sangat panjang | Job yang benar-benar macet menahan slotnya lama |
aws sqs set-queue-attributes \
--queue-url https://sqs.ap-southeast-1.amazonaws.com/123456789012/portal-default \
--attributes VisibilityTimeout=180,MessageRetentionPeriod=1209600
Gejalanya khas dan membingungkan: email terkirim dua kali, poin bertambah dobel, atau berkas
ditulis berulang — sementara log menunjukkan job "berhasil" beberapa kali. Penyebabnya hampir selalu visibility
timeout yang lebih pendek daripada durasi job sesungguhnya. Selaraskan tiga angka: --timeout pada
queue:work, visibility timeout SQS, dan stopTimeout ECS.
Dead letter queue
aws sqs set-queue-attributes \
--queue-url .../portal-default \
--attributes '{
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:…:portal-dlq\",\"maxReceiveCount\":\"3\"}"
}'
Setelah gagal tiga kali, pesan dipindahkan ke DLQ alih-alih terus diulang. Tanpa DLQ, job yang selalu gagal — misalnya karena data yang rusak — akan diambil, gagal, dan kembali lagi tanpa henti, memakan kapasitas worker selamanya.
Alarm CloudWatch:
ApproximateNumberOfMessagesVisible pada portal-dlq > 0 → beri tahu tim
DLQ yang tidak dipantau sama saja dengan tidak punya DLQ. Ia menjadi tempat pekerjaan menghilang dengan rapi. Alarm pada jumlah pesannya adalah satu dari sedikit alarm yang benar-benar wajib ada — karena isinya adalah pekerjaan nyata yang tidak pernah selesai: email yang tidak terkirim, pembayaran yang tidak tercatat.
Batasan SQS yang mengubah cara menulis job
| Batas | Konsekuensi di Laravel |
|---|---|
| Payload 256 KB | Kirim ID; jangan serialisasi koleksi besar |
| Penundaan maksimum 15 menit | delay(now()->addHours(2)) tidak bekerja seperti dugaanmu |
| Urutan tidak dijamin (Standard) | Jangan andalkan urutan pemrosesan |
| At-least-once | Job harus idempoten — tanpa kecuali |
| Tanpa Horizon | Pantau lewat metrik CloudWatch |
| Retensi maksimum 14 hari | Pesan yang lebih tua dari itu hilang |
// Untuk penundaan panjang: jadwalkan, jangan menunda pesan
Schedule::call(function () {
Langganan::query()
->where('berakhir_pada', '<=', now()->addDay())
->where('diingatkan', false)
->each(fn ($l) => KirimPengingat::dispatch($l->id));
})->hourly();
Beberapa antrean dengan prioritas
portal-penting visibility 60s worker terpisah, selalu ada
portal-default visibility 180s worker utama
portal-media visibility 900s worker besar untuk pemrosesan gambar
portal-dlq retensi 14 hari diawasi alarm
php artisan queue:work sqs --queue=portal-penting,portal-default \
--tries=3 --backoff=10,60,300 --max-time=3600 --timeout=120
Satu service ECS per kelompok antrean. Worker media yang butuh memori besar tidak perlu berjumlah banyak; worker notifikasi yang cepat perlu banyak tapi kecil. Memisahkannya berarti setiap kelompok bisa diskalakan dan diberi ukuran sesuai sifatnya — dan job berat tidak pernah menahan yang ringan.
Redis atau SQS
| Kebutuhan | Pilih |
|---|---|
| Dasbor bawaan, penundaan panjang, batch | Redis + Horizon |
| Pekerjaan tidak boleh hilang sama sekali | SQS |
| Lonjakan sangat besar dan tidak terduga | SQS — tidak ada kapasitas yang perlu disiapkan |
| Menyeberang ke layanan atau tim lain | SQS |
| Ingin sesedikit mungkin infrastruktur | SQS — tidak ada klaster yang dikelola |
Keduanya bisa dipakai bersamaan. Laravel mendukung banyak koneksi antrean, jadi
Queue::route() dari Fase 3 bisa mengarahkan job penting ke SQS dan job biasa ke Redis. Yang perlu
dihindari cuma satu: memakai satu klaster Redis untuk cache dan antrean dengan kebijakan
allkeys-lru.
Latihan: buat antrean SQS dengan DLQ dan maxReceiveCount=3. Kirim job yang selalu gagal,
amati ia berpindah ke DLQ setelah percobaan ketiga, lalu pasang alarm CloudWatch untuk jumlah pesan di DLQ.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.