명령어/DB

[PostgreSQL] LISTEN/NOTIFY 폴링 없이 DB 이벤트를 실시간으로 받는다

jykim23 2026. 7. 23. 21:56
반응형

설치·접속: PostgreSQL 설치와 접속

부제: "새 주문 들어왔나?"를 1초마다 SELECT로 캐묻는 대신, 변화가 생기는 그 순간 DB가 대기 중인 세션에 직접 알려 주게 하고 싶을 때

-- [세션 A] 채널을 구독하고 기다린다. 알림이 오면 즉시 출력된다
LISTEN m10_chan;
SELECT pg_sleep(4);   -- 대기하는 동안 알림 수신
-- [세션 B] 같은 채널로 발신 (다른 접속에서)
NOTIFY m10_chan, 'order 42 paid';
-- 세션 A 화면에 뜨는 결과
LISTEN
 pg_sleep 
----------

(1 row)

Asynchronous notification "m10_chan" with payload "order 42 paid"
received from server process with PID 11124.

LISTEN으로 채널을 구독한 세션은, 다른 세션이 같은 채널에 NOTIFY를 보내면 그 즉시 페이로드를 전달받는다. 애플리케이션이 상태 변화를 알려고 테이블을 반복 조회(폴링)하면 부하도 크고 지연도 생기는데, LISTEN/NOTIFY는 이벤트가 발생하는 순간에만 신호가 흐르므로 지연이 거의 없고 DB도 놀지 않는다. 알림은 트랜잭션이 커밋될 때 배달되므로, 롤백되면 알림도 나가지 않아 데이터와 신호가 어긋나지 않는다. 캐시 무효화, 작업 큐 깨우기, 실시간 대시보드 갱신 신호로 잘 맞는다.

이렇게도 쓴다

채널명을 변수로 다뤄야 할 때는 함수형을 쓴다. (조합: pg_notify)

SELECT pg_notify('m10_chan', 'payload as text');   -- NOTIFY의 함수 버전

 

행이 바뀔 때 트리거가 자동으로 알림을 쏘게 한다. (조합: 트리거 + pg_notify)

CREATE FUNCTION m10_notify_order() RETURNS trigger AS $$
BEGIN
  PERFORM pg_notify('m10_chan', 'new order id=' || NEW.id || ' amt=' || NEW.amount);
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER trg_m10_notify AFTER INSERT ON m10_orders
  FOR EACH ROW EXECUTE FUNCTION m10_notify_order();
-- INSERT 한 방에 리스너가 "new order id=1 amt=99.5" 수신

 

구독을 해제한다.

UNLISTEN m10_chan;   -- 전체 해제는 UNLISTEN *

 

셸에서 채널을 모니터링한다(반복 조회로 알림 플러시). (조합: psql \watch)

psql -d shop -c "LISTEN m10_chan" -c "SELECT 1" -c "\watch 2"

 

같은 페이로드가 몰리면 커밋 시 하나로 합쳐진다(중복 제거).

-- 한 트랜잭션 안에서 동일 채널·동일 payload NOTIFY 여러 번 → 리스너엔 1건만
반응형