NOTIFY

NOTIFY

알림 이벤트(notification event)를 보내는 명령이에요. 같은 데이터베이스에서 이전에 LISTEN channel을 실행한 각 클라이언트 애플리케이션에, 선택적인 “payload” 문자열과 함께 알림을 전달해요. 애플리케이션 간의 간단한 프로세스 간 통신(IPC) 메커니즘으로 사용돼요.

출처: PostgreSQL 문서

본문

개요 (Synopsis)

NOTIFY channel [ , payload ]

설명 (Description)

NOTIFY 명령은 현재 데이터베이스에서 지정된 채널 이름에 대해 이전에 LISTEN channel을 실행한 각 클라이언트 애플리케이션에, 선택적인 “payload” 문자열과 함께 알림 이벤트를 보내요. 알림은 모든 사용자에게 보입니다.

NOTIFY는 같은 PostgreSQL 데이터베이스에 접근하는 프로세스 집합을 위한 간단한 프로세스 간 통신 메커니즘을 제공해요. 알림과 함께 payload 문자열을 보낼 수 있고, 데이터베이스 안의 테이블을 사용해 알림자(notifier)에서 수신자(listener)들로 추가 데이터를 전달함으로써 구조화된 데이터를 전달하는 더 높은 수준의 메커니즘을 구축할 수 있어요.

알림 이벤트에 대해 클라이언트로 전달되는 정보에는 알림 채널 이름, 알림을 보내는 세션의 서버 프로세스 PID, 그리고 payload 문자열(지정하지 않았다면 빈 문자열)이 포함돼요.

특정 데이터베이스에서 사용할 채널 이름과 각각이 무엇을 의미하는지 정의하는 것은 데이터베이스 설계자의 몫이에요. 흔히 채널 이름은 데이터베이스에 있는 어떤 테이블의 이름과 같고, 알림 이벤트는 본질적으로 “이 테이블을 변경했으니 뭐가 새로워졌는지 한번 봐봐”를 의미해요. 하지만 NOTIFYLISTEN 명령은 그런 연관성을 강제하지 않아요. 예를 들어 데이터베이스 설계자는 단일 테이블에 대한 서로 다른 종류의 변경을 알리기 위해 여러 다른 채널 이름을 사용할 수 있어요. 또는 payload 문자열을 사용해 다양한 경우를 구분할 수도 있어요.

NOTIFY를 특정 테이블의 변경 발생을 알리는 데 사용한다면, 유용한 프로그래밍 기법은 테이블 갱신에 의해 트리거되는 명령문 트리거(statement trigger)에 NOTIFY를 넣는 거예요. 이렇게 하면 테이블이 변경될 때 알림이 자동으로 발생하므로, 애플리케이션 프로그래머가 실수로 그것을 잊어버릴 수 없어요.

NOTIFY는 SQL 트랜잭션과 몇 가지 중요한 방식으로 상호작용해요. 첫째, NOTIFY가 트랜잭션 안에서 실행되면 알림 이벤트는 트랜잭션이 커밋될 때까지(그리고 커밋돼야만) 전달되지 않아요. 트랜잭션이 중단되면 그 안의 모든 명령이 효과가 없으므로 NOTIFY도 그렇고, 이것이 적절해요. 하지만 알림 이벤트가 즉시 전달되기를 기대하고 있다면 당황스러울 수 있어요. 둘째, 수신 세션이 트랜잭션 안에 있는 동안 알림 신호를 받으면, 알림 이벤트는 트랜잭션이 완료된(커밋되든 중단되든) 직후에만 연결된 클라이언트에 전달돼요. 마찬가지로, 나중에 중단될 트랜잭션 안에서 알림이 전달된다면 어떤 식으로든 알림을 되돌리고 싶을 텐데, 서버는 일단 클라이언트에 알림을 보내면 “되돌릴” 수 없어요. 따라서 알림 이벤트는 트랜잭션 사이에만 전달돼요. 결과적으로 NOTIFY를 실시간 신호용으로 사용하는 애플리케이션이 트랜잭션을 짧게 유지하도록 노력해야 한다는 뜻이에요.

같은 트랜잭션 안에서 동일한 채널 이름이 동일한 payload 문자열로 여러 번 신호되면, 알림 이벤트의 인스턴스 하나만 수신자에게 전달돼요. 반면 payload 문자열이 서로 다른 알림은 항상 별개의 알림으로 전달돼요. 마찬가지로 서로 다른 트랜잭션의 알림은 하나의 알림으로 합쳐지지 않아요. 중복 알림의 이후 인스턴스를 버리는 것을 제외하고, NOTIFY는 같은 트랜잭션의 알림이 보낸 순서대로 전달됨을 보장해요. 또한 서로 다른 트랜잭션의 메시지는 트랜잭션이 커밋된 순서대로 전달됨을 보장해요.

NOTIFY를 실행하는 클라이언트가 같은 알림 채널을 스스로 듣고 있는 것도 흔해요. 그 경우 다른 수신 세션들과 마찬가지로 알림 이벤트를 되돌려받아요. 애플리케이션 로직에 따라 이것은 쓸모없는 작업으로 이어질 수 있어요. 예를 들어 방금 그 세션이 써낸 것과 같은 갱신을 찾기 위해 데이터베이스 테이블을 읽는 것처럼요. 알림 이벤트 메시지에 제공되는 알림 세션의 서버 프로세스 PID가 자신의 세션 PID(libpq에서 사용 가능)와 같은지 확인하면 이런 불필요한 작업을 피할 수 있어요. 같으면 그 알림 이벤트는 자기 작업이 되돌아온 것이므로 무시할 수 있어요.

파라미터 (Parameters)

*channel* — 신호를 보낼 알림 채널의 이름이에요(모든 식별자).

*payload* — 알림과 함께 전달할 “payload” 문자열이에요. 단순한 문자열 리터럴로 지정해야 해요. 기본 구성에서는 8000바이트보다 짧아야 해요. (바이너리 데이터나 다량의 정보를 전달해야 한다면 데이터베이스 테이블에 넣고 레코드의 키를 보내는 것이 가장 좋아요.)

참고 (Notes)

보내졌지만 아직 모든 수신 세션이 처리하지 않은 알림을 보관하는 큐(queue)가 있어요. 이 큐가 가득 차면 NOTIFY를 호출하는 트랜잭션은 커밋 시 실패해요. 큐는 꽤 큽니다(표준 설치에서 8GB)거의 모든 사용 사례에 충분한 크기여야 해요. 하지만 세션이 LISTEN을 실행한 다음 아주 오랫동안 트랜잭션 안에 들어가 있으면 정리는 일어날 수 없어요. 큐가 절반 차면 로그 파일에서 정리를 막고 있는 세션을 가리키는 경고를 볼 수 있어요. 그 경우 그 세션이 현재 트랜잭션을 끝내 정리가 진행될 수 있도록 해야 해요.

pg_notification_queue_usage 함수는 현재 보류 중인 알림이 차지하고 있는 큐의 비율을 반환해요. 자세한 내용은 9.27절을 참고하세요.

NOTIFY를 실행한 트랜잭션은 2단계 커밋을 위해 준비될 수 없어요.

pg_notify

알림을 보내려면 pg_notify(text, text) 함수를 사용할 수도 있어요. 이 함수는 첫 인자로 채널 이름을, 두 번째 인자로 payload를 받아요. 이 함수는 채널 이름과 payload가 상수가 아닐 때 NOTIFY 명령보다 사용하기 훨씬 쉬워요.

예제 (Examples)

psql에서 listen/notify 시퀀스를 구성하고 실행하려면:

LISTEN virtual;
NOTIFY virtual;
Asynchronous notification "virtual" received from server process with PID 8448.
NOTIFY virtual, 'This is the payload';
Asynchronous notification "virtual" with payload "This is the payload" received from server process with PID 8448.

LISTEN foo;
SELECT pg_notify('fo' || 'o', 'pay' || 'load');
Asynchronous notification "foo" with payload "payload" received from server process with PID 14728.

호환성 (Compatibility)

SQL 표준에는 NOTIFY 명령문이 없어요.

더 알아보기 (Learn more)

알림을 수신하는 방법은 LISTEN 문서를, 수신 등록을 해제하는 방법은 UNLISTEN 문서를 함께 보면 좋아요.