PostgreSQL NOTIFY/LISTEN ile Gerçek Zamanlı Bildirim Sistemi

PostgreSQL pg_notify ve LISTEN mekanizması nasıl çalışır? Trigger ile bildirim gönderme, Node.js'te dinleme ve Supabase Realtime altyapısı rehberi.

Polling’e Son: Veritabanı Sana Söylesin

Geleneksel yaklaşım: Her 5 saniyede “yeni veri var mı?” diye sorgulamak (polling). Verimsiz, yavaş, sunucu yükü.

Doğru yaklaşım: Veritabanı kendisi “yeni veri geldi” desin. PostgreSQL’in yerleşik NOTIFY/LISTEN mekanizması bunu sağlar.

NOTIFY/LISTEN Nasıl Çalışır?

Uygulama A                   PostgreSQL                   Uygulama B
    │                            │                            │
    │  INSERT INTO orders(...)   │                            │
    │───────────────────────────>│                            │
    │                            │  NOTIFY 'new_order'        │
    │                            │───────────────────────────>│
    │                            │        payload: {...}      │
    │                            │                            │
  1. NOTIFY: Bir kanala mesaj gönderir
  2. LISTEN: Bir kanalı dinlemeye başlar
  3. Payload: Mesajla birlikte veri taşır (max 8000 byte)

NOTIFY ile Mesaj Gönderme

-- Basit bildirim
NOTIFY new_order, 'Sipariş #1234 oluşturuldu';

-- JSON payload ile
SELECT pg_notify(
  'stock_alert',
  json_build_object(
    'product_id', 42,
    'stock', 3,
    'message', 'Kritik stok seviyesi!'
  )::text
);

Trigger ile Otomatik Bildirim

CREATE OR REPLACE FUNCTION notify_new_order()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify(
    'new_order',
    json_build_object(
      'id', NEW.id,
      'customer', NEW.customer_name,
      'total', NEW.total_amount,
      'created_at', NEW.created_at
    )::text
  );
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER order_created_notify
AFTER INSERT ON orders
FOR EACH ROW
EXECUTE FUNCTION notify_new_order();

Bu trigger sayesinde orders tablosuna her INSERT olduğunda bağlı tüm dinleyiciler otomatik bildirim alır.

Node.js ile LISTEN

import { Client } from 'pg';

const client = new Client({
  connectionString: process.env.DATABASE_URL,
});

async function startListening() {
  await client.connect();
  
  // Kanalı dinlemeye başla
  await client.query('LISTEN new_order');
  await client.query('LISTEN stock_alert');
  
  // Bildirim geldiğinde
  client.on('notification', (msg) => {
    console.log('Kanal:', msg.channel);
    
    const payload = JSON.parse(msg.payload || '{}');
    console.log('Veri:', payload);
    
    // İstediğiniz aksiyonu alın
    if (msg.channel === 'stock_alert') {
      sendSlackNotification(payload);
    }
    
    if (msg.channel === 'new_order') {
      broadcastToWebSocket(payload);
    }
  });
  
  console.log('Dinleniyor: new_order, stock_alert');
}

startListening().catch(console.error);

Stok Kritik Seviye Uyarısı

-- Stok seviyesi 5'in altına düştüğünde bildirim
CREATE OR REPLACE FUNCTION check_stock_level()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.quantity <= 5 AND (OLD.quantity IS NULL OR OLD.quantity > 5) THEN
    PERFORM pg_notify(
      'stock_alert',
      json_build_object(
        'product_id', NEW.product_id,
        'product_name', (SELECT name FROM products WHERE id = NEW.product_id),
        'quantity', NEW.quantity,
        'warehouse', NEW.warehouse_id
      )::text
    );
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER stock_level_check
AFTER UPDATE ON inventory
FOR EACH ROW
EXECUTE FUNCTION check_stock_level();

Supabase Realtime vs NOTIFY/LISTEN

Supabase Realtime aslında NOTIFY/LISTEN üzerine kurulmuştur:

ÖzellikHam NOTIFY/LISTENSupabase Realtime
AltyapıKendi sunucunuzSupabase managed
BağlantıPostgreSQL connectionWebSocket
RLS desteğiManuelOtomatik
Client SDKYoksupabase-js
ÖlçeklenmeSınırlıAuto-scale

Polling vs NOTIFY Performans Karşılaştırması

MetrikPolling (5sn)NOTIFY/LISTEN
Gecikme0-5 saniye~10ms
Sorgu sayısı/dakika120 (sadece bildirim)
Sunucu yüküSabit (gereksiz)Sadece değişiklikte
BağlantıHer sorgudaSürekli (1 connection)

Dikkat Edilecekler

  1. Payload limiti: 8000 byte. Büyük veri göndermeyin — sadece ID/key gönderin.
  2. Bağlantı kopması: LISTEN bağlantısı koparsa bildirimler kaybolur. Reconnect mantığı ekleyin.
  3. Transaction: NOTIFY, transaction commit edilene kadar gönderilmez.
  4. Connection pool: LISTEN için ayrı bir bağlantı kullanın, pool’dan değil.

İlgili Yazılar


Bu rehber PostgreSQL NOTIFY Docs ve pg_listen dokümantasyonuna dayanarak hazırlanmıştır.

📚 İlgili Yazılar