Sistemul Nativ Pub/Sub în PostgreSQL (LISTEN și NOTIFY) în PostgreSQL

Interogări Complexe și Ierarhii Toate versiunile PostgreSQL

Ghid complet pentru sistemul de mesagerie asincronă LISTEN și NOTIFY în PostgreSQL: comunicare event-driven în timp real, integrarea cu trigger-e SQL și eliminarea cozilor externe precum Redis.

Sintaxă SQL
LISTEN comenzi_noi; NOTIFY comenzi_noi, '{"id": 105, "status": "platit"}';

PostgreSQL include nativ un mecanism ultra-rapid de Publicare/Abonare (Pub/Sub) asincronă controlat prin comenzile LISTEN și NOTIFY. Acest mecanism permite conexiunilor client (microservicii Node.js, Python, Go, PHP) să se aboneze la canale de evenimente și să primească alerte în timp real în momentul în care datele din tabele sunt modificate, eliminând necesitatea interogării repetate prin polling (SELECT ... WHERE citit = false) sau a menținerii unui server Redis suplimentar.

Trimiterea automată de notificări din Trigger-e SQL
-- 1. Creăm funcția de trigger care trimite evenimentul la modificarea comenzilor:
CREATE OR REPLACE FUNCTION notifica_schimbare_comanda()
RETURNS TRIGGER AS $$
DECLARE
    payload JSON;
BEGIN
    payload = json_build_object(
        'eveniment', TG_OP,
        'comanda_id', NEW.id,
        'status', NEW.status,
        'client_id', NEW.client_id,
        'timestamp', NOW()
    );
    
    -- Trimitem notificarea pe canalul 'evenimente_comenzi' cu payload-ul JSON
    PERFORM pg_notify('evenimente_comenzi', payload::TEXT);
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 2. Atașăm trigger-ul la tabelul de comenzi:
CREATE TRIGGER trg_notificare_comanda
AFTER INSERT OR UPDATE ON comenzi
FOR EACH ROW EXECUTE FUNCTION notifica_schimbare_comanda();

Cum se consumă evenimentele într-un Worker Backend

Conexiunea ascultătoare emite comanda LISTEN și rămâne într-o stare de așteptare pasivă (fără consum de CPU):

Exemplu de ascultare în terminalul psql sau client Node.js
-- În psql (Sesiunea 1):
LISTEN evenimente_comenzi;

-- În altă conexiune (Sesiunea 2):
INSERT INTO comenzi (id, client_id, status) VALUES (554, 12, 'procesare');

-- Imediat, Sesiunea 1 primește notificarea asincronă:
-- Asynchronous notification "evenimente_comenzi" with payload "{"eveniment":"INSERT","comanda_id":554,"status":"procesare"}" received from server process with PID 4812.

Garanții Tranzacționale și Bune Practici

  • Livrare doar la COMMIT: Dacă o tranzacție care execută NOTIFY suferă un ROLLBACK, notificarea este anulată automat și nu va fi livrată niciodată abonaților! Aceasta este o diferență majoră față de un publisher extern (ex: Kafka sau Redis), unde un mesaj trimis înainte de commit poate conține date care nu au fost salvate pe disc.
  • Limita de Payload: Dimensiunea maximă a payload-ului unui mesaj NOTIFY este de 8000 de octeți. Nu transmiteți documente masive prin payload; transmiteți doar identificatorul resursei (ex: {"id": 554, "action": "update"}), lăsând consumatorul să interogheze baza de date dacă are nevoie de întreg corpul înregistrării.
  • Natură efemeră: Notificările sunt livrate doar conexiunilor care ascultă activ în acel moment. Dacă un worker este oprit pentru mentenanță în secunda trimiterii, mesajul nu este stocat pe disc pentru reîncercare ulterioară. Pentru cozi persistente de sarcini garantate, folosiți modelul SELECT ... FOR UPDATE SKIP LOCKED.