PGMQ: Saat Postgres Sudah Cukup Jadi Message Queue

PGMQ: Saat Postgres Sudah Cukup Jadi Message Queue
Kalau Postgres sudah berjalan, message queue pertama hampir pasti sebaiknya hidup di dalamnya juga. PGMQ menjadikan tabel Postgres sebagai queue sungguhan: visibility timeout, enqueue transaksional, dan dead-letter handling, tanpa broker baru, tanpa sistem kedua untuk di-maintain.
Di titik tertentu dalam hidup setiap backend, ada pekerjaan yang harus terjadi nanti atau di tempat lain: kirim email invoice, hitung ulang laporan, tembakkan webhook. Jawaban refleksnya "tambahkan message queue," dan implementasi refleksnya Kafka atau RabbitMQ. Di banyak sistem yang saya bangun dan review, refleks itu menempelkan sistem terdistribusi ke produk yang database-nya sebenarnya sudah bisa mengerjakan tugas itu.
Queue yang hidup di dalam database
PGMQ adalah extension Postgres yang menerapkan message queue sebagai
tabel plus API SQL: pgmq.send(), pgmq.read(), pgmq.delete(),
pgmq.archive(). Tidak ada proses broker, tidak ada port baru, tidak ada
artefak deployment baru.
Client library tersedia kalau mau ergonomi yang lebih halus — di Node,
pgmq-js membungkus pembuatan queue, send, dan read dalam beberapa
panggilan. Tapi ujungnya semua adalah SQL ke database yang sudah berjalan.
Framing itu lebih penting dari daftar fitur mana pun: queue-nya mewarisi semua yang sudah dimiliki Postgres. Backup, replikasi, monitoring, access control, point-in-time recovery — tidak ada yang perlu dibangun dua kali untuk sistem kedua.
Visibility timeout, bukan lock
Bayangkan restoran yang mencatat satu meja sebagai "sedang dilayani" begitu satu pelayan mengambil pesanannya. Pelayan lain tidak boleh menyerobot meja itu — tapi kalau pelayan pertama menghilang tanpa menyelesaikan pesanan, statusnya kembali terbuka dan pelayan lain bisa ambil alih. Visibility timeout bekerja sama persis.
Model pengiriman PGMQ adalah model yang dipopulerkan SQS. Consumer membaca pesan dengan visibility timeout — misalnya 30 detik. Pesannya tidak keluar dari queue; selama rentang timeout itu dia hanya tak terlihat oleh consumer lain. Selesaikan pekerjaannya lalu delete atau archive pesannya, dan ia hilang permanen. Crash di tengah pekerjaan tanpa sempat apa-apa, dan pesannya muncul kembali begitu timeout habis, siap untuk consumer berikutnya.
Hasilnya: at-least-once delivery dengan pemulihan dari crash dan tanpa lock yang nyangkut. Ada satu kewajiban: consumer harus idempotent, karena "at least once" sesekali berarti dua kali. Rancang setiap handler agar pengiriman ulang tidak berbahaya, dan semantiknya mengurus dirinya sendiri.
Fitur pembunuhnya: enqueue transaksional
Ini yang tidak bisa diberikan Kafka dan RabbitMQ berapa pun harganya: meng-enqueue pesan dalam satu commit yang sama dengan data bisnisnya.
Dengan broker eksternal ada dua sistem, jadi ada dua mode kegagalan. Commit order tapi gagal publish event-nya, dan sistem hilir tidak pernah dengar. Publish event tapi order-nya di-rollback, dan hilir memproses sesuatu yang tidak pernah ada.
Jawaban industri adalah outbox pattern — tulis ke tabel outbox secara transaksional, relay belakangan — yang sebenarnya cara sopan untuk bilang "bangun saja setengah queue di dalam Postgres." Dengan PGMQ, queue-nya memang tabel di database yang sama:
BEGIN;
INSERT INTO orders (...) VALUES (...);
SELECT pgmq.send('notifications', '{"order_id": 118}');
COMMIT;
Satu commit. Order dan pesannya sama-sama ada, atau sama-sama tidak. Di sebuah backend operasional yang saya bangun untuk perusahaan logistik, properti tunggal ini menghapus satu job rekonsiliasi yang satu-satunya tugasnya menangkap selisih dual-write antara database dan broker.
Beban operasional yang terlewati
Kafka berarti broker, controller quorum, partisi, consumer group, tuning retention, dan dashboard yang dipelototi saat rebalancing kacau. RabbitMQ lebih ringan, tapi tetap satu cluster stateful lagi dengan jalur upgrade dan mode kegagalannya sendiri. Keduanya sepadan kalau memang benar-benar dibutuhkan. Tapi keduanya tidak pernah gratis.
Queue di Postgres cuma satu schema tambahan. Ia ter-backup oleh backup yang sudah berjalan, terpantau oleh monitoring yang sudah jalan, dan ter-upgrade bersama database-nya. Untuk tim kecil, selisih itu menentukan apakah rotasi on-call masih manusiawi.
Plafon throughput, dan kapan waktunya lulus
Angka jujurnya: di hardware sederhana saya pernah mem-benchmark PGMQ pada latensi baca satu digit milidetik dan ribuan pesan per detik — beberapa orde di atas beban backend line-of-business pada umumnya. Tapi plafonnya nyata. Consumer melakukan polling, bukan menerima push, tabel queue yang panas butuh perhatian vacuum, dan semuanya berbagi I/O dengan aplikasinya.
Luluslah saat bentuk beban berubah, bukan sekadar ukurannya: puluhan ribu pesan per detik yang berkelanjutan, kebutuhan replay riwayat, atau banyak consumer group independen membaca stream yang sama. Itu semantik event log, dan Kafka adalah event log. PGMQ adalah work queue. Alat yang berbeda — kebanyakan backend seumur hidupnya cuma butuh yang kedua.
Dead letter
Pesan beracun — yang meng-crash consumer-nya setiap kali — tidak boleh
berputar selamanya. PGMQ mencatat read count per pesan, jadi penanganan
dead-letter cukup beberapa baris SQL: saat read_ct melewati ambang
batas, pindahkan pesannya ke dead-letter queue dan pasang alert pada
kedalamannya. Tabel archive melengkapinya: setiap pesan yang
selesai tetap bisa di-query, jejak audit yang biasanya harus dibangun
sendiri.
Intinya
Kalau Postgres sudah berjalan, message queue pertama hampir pasti sebaiknya hidup di dalamnya. Dapatkan semantik visibility timeout, enqueue transaksional yang secara struktural mustahil ditawarkan broker, dan cerita operasional yang identik dengan database yang sudah dikenal. Pindah ke Kafka saat memang butuh event log — bukan karena diagram terlihat lebih megah dengannya.
Ini filosofi yang sama dengan grouping lintas zona waktu di PostgreSQL: dorong pekerjaannya ke database yang memang sudah ada. Banyak backend IoT yang saya bangun menjalankan job queue-nya persis seperti ini.
Artikel Terkait
Mau bangun hal serupa?
Jasa Pengembangan Backend IoT & Integrasi Multi-Protokol
Backend yang menyerap telemetri perangkat lintas MQTT, WebSocket, Modbus, dan BLE, lalu menyatukannya jadi dashboard real-time yang andal.
Lihat cara saya bisa bantu