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.
-- 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):
-- Î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ă
NOTIFYsuferă unROLLBACK, 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
NOTIFYeste 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.