RabbitMQ에서 메시지가 데드레터 큐로 이동하는 주요 원인은 다음과 같습니다:
- 메시지가 거부되었으며 재큐잉이 비활성화된 경우 (basic.reject 또는 basic.nack 사용 시 requeue=false)
- 큐의 최대 메시지 수 제한을 초과한 경우
- 설정된 TTL(Time To Live) 시간이 경과하여 메시지가 만료된 경우
다음은 데드레터 큐를 활용한 메시지 발송 예제입니다. 일반 큐에 메시지를 전송하면서 데드레터 설정을 포함합니다.
/// <summary>
/// 데드레터 큐를 통한 메시지 전송
/// </summary>
/// <param name="message">전송할 메시지 내용</param>
public void SendMessageWithDLX(string message)
{
const string normalExchange = "main.exchange";
const string normalRoutingKey = "main.routing";
const string normalQueue = "main.queue";
const string dlxExchange = "deadletter.exchange";
const string dlxRoutingKey = "deadletter.routing";
const string dlxQueue = "deadletter.queue";
this.EstablishConnection();
IModel channel = this._connection.CreateModel();
// 데드레터 교환기 선언
channel.ExchangeDeclare(dlxExchange, ExchangeType.Direct, true, false, null);
// 데드레터 큐 생성
channel.QueueDeclare(dlxQueue, true, false, false);
channel.QueueBind(dlxQueue, dlxExchange, dlxRoutingKey);
// 주 교환기 선언
channel.ExchangeDeclare(normalExchange, ExchangeType.Direct, true, false);
// 주 큐 생성 및 데드레터 설정
channel.QueueDeclare(normalQueue, true, false, false, new Dictionary<string, object> {
{ "x-dead-letter-exchange", dlxExchange },
{ "x-dead-letter-routing-key", dlxRoutingKey },
{ "x-message-ttl", 30000 } // 30초 후 만료
});
channel.QueueBind(normalQueue, normalExchange, normalRoutingKey);
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
channel.BasicPublish(
exchange: normalExchange,
routingKey: normalRoutingKey,
basicProperties: properties,
body: Encoding.UTF8.GetBytes(message)
);
}
데드레터 큐의 메시지를 소비하는 코드는 아래와 같습니다:
/// <summary>
/// 데드레터 큐 메시지 수신 처리
/// </summary>
/// <param name="messageHandler">메시지 처리 함수</param>
public void ConsumeDeadLetterMessages(Func<string, bool> messageHandler)
{
EstablishConnection();
IModel channel = this._connection.CreateModel();
// 데드레터 교환기 및 큐 설정
channel.ExchangeDeclare("deadletter.exchange", ExchangeType.Direct, true, false, null);
channel.QueueDeclare("deadletter.queue", true, false, false);
channel.QueueBind("deadletter.queue", "deadletter.exchange", "deadletter.routing");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, args) => {
string receivedMsg = Encoding.UTF8.GetString(args.Body.ToArray());
if (messageHandler(receivedMsg))
{
channel.BasicAck(args.DeliveryTag, false);
}
else
{
// 메시지 거부 및 재큐잉
channel.BasicReject(args.DeliveryTag, true);
}
};
channel.BasicQos(0, 1, false);
channel.BasicConsume("deadletter.queue", false, consumer);
}
테스트 결과, 일반 큐에 전송된 메시지는 30초 후 자동으로 데드레터 큐로 이동하며, 이후 해당 큐에서 성공적으로 소비됩니다.