RabbitMQ에서 .NET Core를 이용한 데드레터 큐 구현

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초 후 자동으로 데드레터 큐로 이동하며, 이후 해당 큐에서 성공적으로 소비됩니다.

태그: .NET-Core RabbitMQ message-queue dead-letter-queue messaging

6월 6일 21:36에 게시됨