如何使用MassTransit从RabbitMQ DeadLetter队列中检索消息?

时间:2019-03-27 18:50:58

标签: c# rabbitmq masstransit

我试图使用 MassTransit RabbitMQ 在一段时间后未收到消息时通知用户。

根据我的阅读,消息发布时使用 TimeToLive 属性设置了超时时间。当指定的时间用完时,该邮件应自动添加到 Dead Letter 队列中,并在末尾以“ _skipped”命名。

如何从死信队列中检索消息?在下面的尝试中,该消息立即添加到两个队列中,并且永不超时。

我认为我可以使用sagas来做到这一点,但是对于这样一个简单的问题,这似乎是一个过于复杂的解决方案,因此,我尽可能避免使用它。

static void Main(string[] args)
{
    var bus = CreateBus("rabbitmq://localhost/", "guest", "guest", true);

    var msg = new TestMessage("First Message");
    LogMessageSent(msg);
    bus.Publish(msg, c => c.TimeToLive = TimeSpan.FromSeconds(15));

    Console.ReadKey();

    bus.Stop();

    bus = CreateBus("rabbitmq://localhost/", "guest", "guest", false);

    msg = new TestMessage("SecondMessage");
    LogMessageSent(msg);
    bus.Publish(msg, c => c.TimeToLive = TimeSpan.FromSeconds(15));

    Console.ReadKey();

    bus.Stop();
}

private static IBusControl CreateBus(string rabbitUrl, string username, string password, bool enableEndpoint)
{
    var bus = Bus.Factory.CreateUsingRabbitMq(c =>
    {
        var host = c.Host(new Uri(rabbitUrl), h =>
        {
            h.Username(username);
            h.Password(password);
        });

        if (enableEndpoint)
        {
            c.ReceiveEndpoint(host, "TestQueue", x =>
            {
                x.Handler<TestMessage>(e => LogMessageReceived(e.Message, "TestQueue"));
            });
        }

        c.ReceiveEndpoint(host, "TestQueue_skipped", x =>
        {
            x.Handler<TestMessage>(e => LogMessageReceived(e.Message, "TestQueue_skipped"));
        });
    });

    bus.Start();

    return bus;
}

private static void LogMessageSent(TestMessage msg)
{
    Console.WriteLine(string.Format("{0} - Message \"{1}\" sent.", DateTime.Now.ToString("HH:mm:ss"), msg.Content));
}

private static Task LogMessageReceived(TestMessage msg, string queueName)
{
    Console.WriteLine(string.Format("{0} - Message \"{1}\" received on queue \"{2}\".", DateTime.Now.ToString("HH:mm:ss"), msg.Content, queueName));
    return Task.CompletedTask;
}

public class TestMessage
{
    public string Content { get; }

    public TestMessage(string content)
    {
        Content = content;
    }
}

1 个答案:

答案 0 :(得分:0)

由于您正在呼叫Publish,因此该消息将发送给每个订户。由于每个接收端点都添加了使用者,因此将为该消息类型创建订阅(以及RabbitMQ中的后续交换绑定)。您可以通过在跳过的接收端点上指定BindMessageExchanges = false来禁用此功能。您将需要手动删除代理上的交易所绑定。

关于您的TimeToLive问题,这不是它的工作原理。 TimeToLive传递给代理,并且如果消息过期,则将消息移动到代理指定的死信队列(如果已配置)。它不会移到在MassTransit中具有不同含义的已跳过队列中。在MassTransit中,跳过队列用于传递到接收终结点的消息,但是该终结点上没有配置任何使用方来使用该消息。

对于RabbitMQ,您可以使用以下方法在MassTransit中配置死信队列:

endpoint.BindDeadLetterQueue("dead-letter-queue-name");

这将配置代理,以便将达到其TTL的消息移至指定的交换/队列。然后,您的接收端点上的使用者将能够使用它们(同样,请确保在死信接收端点上设置BindMessageExchanges = false

例如:

c.ReceiveEndpoint(host, "TestQueue_expired", x =>
{
    x.BindMessageExchanges = false;
    x.Handler<TestMessage>(e => LogMessageReceived(e.Message, "TestQueue_expired"));
});

然后是原始接收端点:

c.ReceiveEndpoint(host, "TestQueue", x =>
{
    x.BindDeadLetterQueue("TestQueue_expired");
    x.Handler<TestMessage>(e => LogMessageReceived(e.Message, "TestQueue"));
});
相关问题