Episode ini membahas pola request-reply untuk RPC antar microservices dengan nats request dan timeouts, lalu queue groups untuk load balancing antar consumer serta perbandingannya dengan competing consumers.

Episode 4 memperkuat routing. Episode 5 ini mempersenjatai kalian dengan dua pola yang membuat NATS menjadi tulang punggung microservices: request-reply untuk komunikasi sinkron bergaya RPC, dan queue groups untuk membagi beban kerja secara horizontal.
Keduanya memakai mekanisme yang sudah kalian kenal — subjects — namun dengan semantik yang berbeda. Mari kita bedah satu per satu.
Pola request-reply NATS bekerja dalam tiga langkah: pemanggil mempublish request ke subject dengan reply subject otomatis, server NATS menyisipkan reply subject tersebut ke header pesan, lalu handler mempublish jawaban ke reply subject yang sama.
client --> request ke subject:auth.login [reply: _INBOX.x]
service auth menangkap subject
service mempublish jawaban ke _INBOX.x
client menerima jawabanSubscriber handler yang memproses request tidak perlu tahu identitas pemanggil — cukup memakai msg.respond() untuk membalas.
Cara tercepat melihat pola ini hidup adalah lewat CLI:
nats reply 'auth.login' "OK: token-abc123"
nats request 'auth.login' '{"username":"arman"}'nats reply 'auth.login' "OK: token-abc123" memasang handler yang membalas setiap request, dan nats request 'auth.login' '{...}' mengirim request lalu menunggu jawaban. Output CLI menampilkan OK: token-abc123.
Request-reply adalah operasi sinkron — pemanggil menunggu. Waktu tunggu harus dibatasi agar tidak menggantung:
nats request auth.login '{"username":"arman"}' --timeout=2sFlag --timeout=2s di atas membuat CLI berhenti menunggu setelah 2 detik. Jika handler lambat, pemanggil mendapat error timeout alih-alih menggantung selamanya. Kebiasaan ini wajib ditiru di semua client library.
Di nats-py, request-reply semudah memanggil fungsi:
import asyncio
import nats
async def main():
nc = await nats.connect("nats://localhost:4222")
async def handler(msg):
await msg.respond(b"pong")
await nc.subscribe("ping", cb=handler)
reply = await nc.request("ping", b"ping-request", timeout=2)
print(reply.data)
await nc.close()
asyncio.run(main())await nc.request("ping", b"ping-request", timeout=2) mengirim request dan menunggu jawaban maksimal 2 detik. Di sisi lain, await msg.respond(b"pong") membalas request — dua baris inilah inti pola RPC NATS.
Aturan praktis timeouts di distributed systems: tetapkan timeout di pemanggil, dan tetapkan lebih kecil dari timeout handler di pemanggil atas. Jika service A memanggil B dan B memanggil C, timeout A terhadap B harus lebih kecil dari timeout B terhadap C — agar error tidak menumpuk berlapis.
Tip
Gunakan request-reply untuk operasi yang membutuhkan jawaban segera: verifikasi, otorisasi, pengambilan data. Untuk workload yang boleh diproses asinkron, cukup publish tanpa menunggu reply — lebih cepat dan tidak memblokir.
Queue group mengubah publish/subscribe menjadi competing consumers: sekelompok subscriber yang berbagi nama queue, dan setiap pesan hanya diterima satu anggota. Server NATS melakukan round-robin antar anggota.
nats sub 'jobs.process' --queue workers
nats sub 'jobs.process' --queue workersKedua perintah nats sub 'jobs.process' --queue workers membentuk satu queue group workers — dua proses worker berbagi pesan secara bergantian. Jika ada 10 pesan, masing-masing menerima sekitar 5.
Queue group adalah mekanisme scaling yang sangat sederhana: untuk menangani lebih banyak beban, cukup jalankan instance consumer tambahan dengan nama queue yang sama. Tidak ada perubahan konfigurasi server, tidak ada re-deploy.
publisher --> jobs.process --> worker-1 (queue: workers)
--> worker-2 (queue: workers)
--> worker-3 (queue: workers)Gambar di atas menunjukkan tiga worker berbagi subject jobs.process — setiap pesan mendarat di satu worker saja. Berbeda dengan publish/subscribe biasa di mana semua subscriber menerima salinan.
| Karakteristik | Publish/Subscribe | Queue Group |
|---|---|---|
| Penerima pesan | Semua subscriber | Satu anggota per pesan |
| Tujuan | Broadcast event | Load balancing task |
| Contoh | orders.created | jobs.process |
| Penamaan | Tanpa queue | --queue workers |
nats sub subject --queue name mengubah subscriber biasa menjadi anggota queue group. Pilihan antara broadcast dan load balancing menentukan struktur sistem kalian.
Di client library, queue group ditentukan saat subscribe:
import { connect, StringCodec } from "nats";
const nc = await connect({ servers: "nats://localhost:4222" });
const sc = StringCodec();
nc.subscribe("jobs.process", { queue: "workers" }, (err, msg) => {
console.log("diproses oleh worker:", sc.decode(msg.data));
});
nc.publish("jobs.process", sc.encode("job-1"));nc.subscribe("jobs.process", { queue: "workers" }, handler) memasang subscriber sebagai anggota queue workers. Jalankan dua instance file ini, publish beberapa job, dan perhatikan distribusi yang bergantian.
Info
Queue groups menyeimbangkan beban tapi tidak menjamin urutan. Untuk workload yang butuh pemrosesan berurutan atau jaminan pengiriman, kombinasikan dengan JetStream — tepatnya pola work queue di episode 11.
Episode 5 memperlengkapi kalian dengan dua pola komunikasi produktif: request-reply untuk RPC sinkron dengan nats request dan timeout yang disiplin, serta queue groups untuk load balancing horizontal antar consumer dengan perintah --queue.
Inti yang harus dibawa pulang:
nats request dan nats reply memudahkan pengujian pola RPC dari CLI.Di episode 6 selanjutnya kita akan membahas CLI & client libraries — rangkaian perintah nats pub, nats sub, nats req, nats stream, nats consumer, dan nats account, lalu menulis program lengkap di Go, Python, dan Node.js untuk connect, publish, subscribe, dan request. Di sinilah perangkat kerja harian kalian mulai terbentuk.