2026년 10월 01일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-24033 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-24033 no recipients specified for message 는?
ORA-24033 에러는 Oracle Advanced Queuing(AQ) 또는 Oracle Streams 환경에서 메시지를 전송할 때 수신자(Recipient)를 지정하지 않았을 경우 발생하는 에러입니다. 즉, DBMS_AQ.ENQUEUE 또는 관련 패키지를 통해 메시지를 큐(Queue)에 넣으려 할 때, 메시지를 받을 대상이 명시되지 않으면 Oracle이 이 에러를 반환합니다. 멀티 컨슈머(Multi-Consumer) 큐를 사용하는 환경에서 특히 자주 발생하며, 싱글 컨슈머 큐와는 달리 멀티 컨슈머 큐는 반드시 수신자 목록을 명시적으로 지정해야 합니다.
주요 발생 원인
- 멀티 컨슈머 큐에서 수신자 목록 미지정
Oracle AQ의 멀티 컨슈머 큐(Multi-Consumer Queue)를 사용할 때, DBMS_AQ.ENQUEUE를 호출하면서 message_properties 객체의 recipient_list 속성을 설정하지 않으면 이 에러가 발생합니다. 멀티 컨슈머 큐는 메시지 하나를 여러 소비자가 독립적으로 수신할 수 있는 구조이기 때문에, Oracle은 반드시 수신자가 누구인지 알아야 메시지를 올바르게 라우팅할 수 있습니다. recipient_list에 최소 하나 이상의 SYS.AQ$_RECIPIENT_LIST_T 요소를 추가해야 에러를 피할 수 있습니다.
- 잘못된 큐 테이블 설정 또는 구독자(Subscriber) 미등록
멀티 컨슈머 큐에서 recipient_list를 비워두더라도, 미리 등록된 구독자(Subscriber)가 있으면 Oracle이 해당 구독자에게 메시지를 자동으로 라우팅합니다. 그러나 구독자가 전혀 등록되지 않은 상태에서 recipient_list도 비어있으면 ORA-24033이 발생합니다. DBMS_AQADM.ADD_SUBSCRIBER 프로시저를 이용해 사전에 구독자를 등록하거나, 인큐 시 수신자 목록을 직접 지정해야 합니다.
- 코드 로직 오류로 인한 수신자 배열 초기화 실패
애플리케이션 코드에서 동적으로 수신자 목록을 구성할 때, 조건 분기나 예외 처리 미흡으로 인해 수신자 배열이 빈 상태로 DBMS_AQ.ENQUEUE가 호출되는 경우가 있습니다. 예를 들어, 특정 비즈니스 조건에 따라 수신자를 결정하는 로직에서 조건이 모두 false가 되어 배열에 아무 항목도 추가되지 않는 경우입니다. 이러한 케이스는 런타임 시에만 나타나기 때문에 개발 단계에서 발견하기 어려우며, 철저한 입력값 검증과 방어 코드 작성이 필요합니다.
해결 방법
원인 1 해결: 수신자 목록 명시적 지정
멀티 컨슈머 큐에 메시지를 인큐할 때 recipient_list를 명시적으로 설정합니다.
DECLARE
v_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
v_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
v_payload SYS.AQ$_JMS_TEXT_MESSAGE;
v_recipients DBMS_AQ.AQ$_RECIPIENT_LIST_T;
BEGIN
-- 수신자 목록 초기화 및 수신자 추가
v_recipients(1) := SYS.AQ$_AGENT('CONSUMER_A', NULL, NULL);
v_recipients(2) := SYS.AQ$_AGENT('CONSUMER_B', NULL, NULL);
-- 메시지 프로퍼티에 수신자 목록 할당
v_message_properties.recipient_list := v_recipients;
-- 페이로드 생성 (예시)
v_payload := SYS.AQ$_JMS_TEXT_MESSAGE.construct;
v_payload.set_text('Hello, Multi-Consumer Queue!');
-- 인큐 실행
DBMS_AQ.ENQUEUE(
queue_name => 'MY_SCHEMA.MY_MULTI_QUEUE',
enqueue_options => v_enqueue_options,
message_properties => v_message_properties,
payload => v_payload,
msgid => v_message_handle
);
COMMIT;
DBMS_OUTPUT.PUT_LINE('메시지 인큐 성공: ' || RAWTOHEX(v_message_handle));
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('에러 발생: ' || SQLERRM);
END;
/
원인 2 해결: 구독자 사전 등록
큐에 구독자를 등록하면 recipient_list 없이도 자동으로 메시지가 전달됩니다.
-- 큐 테이블 생성 (멀티 컨슈머)
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
queue_table => 'MY_SCHEMA.MY_QUEUE_TABLE',
queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE',
multiple_consumers => TRUE -- 멀티 컨슈머 설정
);
END;
/
-- 큐 생성
BEGIN
DBMS_AQADM.CREATE_QUEUE(
queue_name => 'MY_SCHEMA.MY_MULTI_QUEUE',
queue_table => 'MY_SCHEMA.MY_QUEUE_TABLE'
);
END;
/
-- 큐 시작
BEGIN
DBMS_AQADM.START_QUEUE(queue_name => 'MY_SCHEMA.MY_MULTI_QUEUE');
END;
/
-- 구독자 등록 (이렇게 하면 recipient_list 없이도 메시지 수신 가능)
BEGIN
DBMS_AQADM.ADD_SUBSCRIBER(
queue_name => 'MY_SCHEMA.MY_MULTI_QUEUE',
subscriber => SYS.AQ$_AGENT('CONSUMER_A', NULL, NULL)
);
DBMS_AQADM.ADD_SUBSCRIBER(
queue_name => 'MY_SCHEMA.MY_MULTI_QUEUE',
subscriber => SYS.AQ$_AGENT('CONSUMER_B', NULL, NULL)
);
DBMS_OUTPUT.PUT_LINE('구독자 등록 완료');
END;
/
-- 등록된 구독자 확인
SELECT name, address, protocol
FROM dba_queue_subscribers
WHERE queue_name = 'MY_MULTI_QUEUE'
AND owner = 'MY_SCHEMA';
원인 3 해결: 동적 수신자 목록 생성 시 방어 코드 추가
DECLARE
v_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
v_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
v_payload VARCHAR2(4000) := 'Test Message';
v_recipients DBMS_AQ.AQ$_RECIPIENT_LIST_T;
v_idx PLS_INTEGER := 1;
v_department_id NUMBER := 10;
BEGIN
-- 동적으로 수신자 결정 (비즈니스 로직 예시)
FOR rec IN (
SELECT consumer_name
FROM aq_consumer_config
WHERE department_id = v_department_id
AND is_active = 'Y'
) LOOP
v_recipients(v_idx) := SYS.AQ$_AGENT(rec.consumer_name, NULL, NULL);
v_idx := v_idx + 1;
END LOOP;
-- 수신자가 없는 경우 방어 코드
IF v_recipients.COUNT = 0 THEN
RAISE_APPLICATION_ERROR(
-20001,
'수신자가 존재하지 않습니다. department_id: ' || v_department_id
);
END IF;
v_message_properties.recipient_list := v_recipients;
DBMS_AQ.ENQUEUE(
queue_name => 'MY_SCHEMA.MY_MULTI_QUEUE',
enqueue_options => v_enqueue_options,
message_properties => v_message_properties,
payload => v_payload,
msgid => v_message_handle
);
COMMIT;
DBMS_OUTPUT.PUT_LINE('인큐 성공, 수신자 수: ' || v_recipients.COUNT);
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('처리 실패: ' || SQLERRM);
END;
/
예방 방법
- 큐 생성 시 컨슈머 타입에 맞는 아키텍처 사전 설계
멀티 컨슈머 큐를 사용하기 전에 반드시 수신자 관리 전략을 결정해야 합니다. “구독자 사전 등록 방식”과 “인큐 시 수신자 직접 지정 방식” 중 하나를 일관되게 선택하고, 팀 내 코딩 표준으로 문서화하세요. 두 방식을 혼용하면 예기치 않은 동작이나 메시지 누락이 발생할 수 있으므로, 프로젝트 초기에 아키텍처를 명확히 결정하는 것이 중요합니다.
“`sql
— 큐 상태 및 구독자 현황 주기적 모니터링 쿼리
SELECT q.name AS queue_name,
q.queue_type,
COUNT(s.name) AS subscriber_count
FROM dba_queues q
LEFT JOIN dba_queue_subscribers s
ON s.queue_name = q.name
AND s.owner = q.owner
WHERE q.owner = ‘MY_SCHEMA’
GROUP BY q.name, q.queue_type
ORDER BY q.name;
“`
- 인큐 전 수신자 유효성 검증 래퍼(Wrapper) 프로시저 작성
모든 인큐 작업을 직접 DBMS_AQ.ENQUEUE로 호출하는 대신, 수신자 유효성 검사 로직이 내장된 래퍼 프로시저를 만들어 팀 전체가 공통으로 사용하도록 강제하세요. 이 래퍼 프로시저 안에서 recipient_list.COUNT > 0 여부를 항상 검사하고, 조건을 만족하지 않으면 명확한 에러 메시지와 함께 예외를 발생시키도록 구성하면 ORA-24033 에러를 사전에 차단할 수 있습니다.
관련 에러
- ORA-24010:
QUEUEdoes not exist — 큐 이름이 잘못되었거나 큐가 생성되지 않은 경우 발생합니다. - ORA-24034: application already subscribed — 동일한 구독자를 중복으로 등록하려 할 때 발생합니다.
- ORA-24035: invalid agent name — 수신자 에이전트 이름이 잘못 지정된 경우 발생합니다.
- ORA-25228: timeout or end-of-fetch during message dequeue — 디큐(Dequeue) 시 타임아웃이 발생했거나 메시지가 없을 때 나타나는 에러로, AQ 운영 시 함께 자주 접하게 됩니다.
- ORA-24002: QUEUE_TABLE does not exist — 큐 테이블이 존재하지 않을 때 발생하며, AQ 환경 초기 구성 시 자주 만나는 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.