Dipublikasikan 25 Juli 2026
Postgres sering dianggap sebagai database relasional biasa, tapi fitur LISTEN/NOTIFY memungkinkannya berperan sebagai message broker ringan. Artikel ini adalah panduan praktis membangun event-driven architecture menggunakan mekanisme pub/sub bawaan Postgres tanpa perlu infrastruktur tambahan seperti Redis atau RabbitMQ.
LISTEN/NOTIFY memungkinkan aplikasi client menerima notifikasi real-time ketika data berubah di database. Dibanding polling berkala, pendekatan ini jauh lebih efisien dalam penggunaan resource dan latensi lebih rendah. Kita akan membahas lima langkah implementasi dari nol hingga production-ready.
Postgres menggunakan konsep channel untuk mengirim notifikasi. Sebelum aplikasi bisa menerima pesan, kamu perlu membuat mekanisme trigger yang memanggil NOTIFY.
-- Membuat tabel contoh
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
status VARCHAR(50) NOT NULL DEFAULT pending,
created_at TIMESTAMP DEFAULT NOW()
);
-- Membuat fungsi trigger
CREATE OR REPLACE FUNCTION notify_order_change()
RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify( order_updates , json_build_object( action , TG_OP, id , NEW.id, status , NEW.status)::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Memasang trigger ke tabel
CREATE TRIGGER trg_order_update
AFTER UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION notify_order_change();Fungsi di atas mengirim payload JSON ke channel order_updates setiap kali ada UPDATE pada tabel orders. Pastikan payload tidak terlalu besar karena NOTIFY membatasi pesan maksimal 8000 byte.
Berikut implementasi listener menggunakan Node.js dengan library pg. Pola serupa bisa diterapkan di Python, Go, atau Rust menggunakan driver Postgres native.
const { Client } = require( pg );
const client = new Client({
host: process.env.DB_HOST,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASS
});
async function startListener() {
await client.connect();
await client.query( LISTEN order_updates );
client.on( notification , (msg) => {
const payload = JSON.parse(msg.payload);
console.log( Event received: , payload);
// Logic bisnis: kirim ke WebSocket, queue job, dll
});
}
startListener().catch(console.error);Kunci di sini adalah menggunakan dedicated connection untuk LISTEN. Jangan gunakan connection pool untuk listener karena connection harus tetap aktif dan idle, bukan dipinjam-pinjamkan.
Salah satu pertanyaan umum: bagaimana kalau ada banyak instance aplikasi? Semua listener yang terhubung ke channel yang sama akan menerima notifikasi secara broadcast. Ini berarti setiap instance mendapat salinan pesan.
Untuk load balancing, gunakan pola berikut:
Broadcast: Cocok untuk cache invalidation. Semua instance menerima signal untuk flush cache lokal.
Queue pattern: Gunakan tabel sebagai queue jika hanya satu worker yang boleh memproses. LISTEN/NOTIFY bisa digunakan sebagai signal ada job baru, bukan delivery mekanisme utama.
Partition by channel: Buat channel dinamis berdasarkan resource ID. Misalnya order_updates_123 sehingga hanya service terkait yang listen.
Menurut laporan dari DBOS, Postgres LISTEN/NOTIFY sebenarnya sangat scalable dan bisa menangani ribuan listener concurrent tanpa degradasi signifikan.
Koneksi LISTEN bersifat persistent. Jika koneksi terputus, listener tidak otomatis recover. Kamu perlu implementasi reconnect logic:
Gunakan health check heartbeat dengan SELECT 1 setiap interval tertentu.
Tangani event end pada connection stream untuk mendeteksi disconnect.
Gunakan exponential backoff sebelum reconnect agar tidak overwhelm server.
Pertimbangkan menggunakan tools seperti PgBouncer atau pgpool dengan care. Transaction pooling bisa mengganggu LISTEN/NOTIFY karena session state hilang saat connection dipool-kan.
client.on( end , () => {
console.warn( Connection lost, reconnecting... );
setTimeout(startListener, 5000); // backoff 5 detik
});Di production, pantau metrik berikut melalui pg_stat_activity dan log Postgres:
| Metrik | Cara Cek | Threshold Warning |
|---|---|---|
| Idle listener count | SELECT count(*) FROM pg_stat_activity WHERE state = idle | > 500 connections |
| Notify queue depth | Log file Postgres: notify queue is full | Any occurrence |
| Payload size | Validasi di trigger atau aplikasi | > 7 KB per message |
Optimasi tambahan: jika payload kompleks, simpan detail di tabel dan kirimkan hanya ID via NOTIFY. Listener kemudian SELECT data lengkap berdasarkan ID yang diterima. Ini mengurangi beban notify queue secara drastis.
Postgres LISTEN/NOTIFY adalah solusi underrated untuk arsitektur event-driven ringan. Tanpa menambah stack infrastructure, kamu sudah punya pub/sub mechanism yang terintegrasi langsung dengan transactional boundary database.
Sumber referensi: DBOS Blog: Postgres LISTEN/NOTIFY Actually Scales, PostgreSQL Documentation: NOTIFY.
Dapatkan feedback, users, dan eksposur dari komunitas kreator, developer, dan entrepreneur digital Indonesia.
Submit Produk → Pelajari Dulu