我试图使用 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;
}
}
答案 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"));
});