为了账号安全,请及时绑定邮箱和手机立即绑定

我的服务堆栈服务中的异常未将消息移动到死信队列

我的服务堆栈服务中的异常未将消息移动到死信队列

C#
繁花如伊 2021-11-21 15:36:52
我有一个带有标准服务堆栈 RabbitMQ 抽象的服务堆栈服务。消息队列是为我的类型 MyRequest 自动创建的,我有一个服务方法,我已经设置了它来处理来自 MyRequest.In Queue 的请求我期待如果我在此方法中抛出异常,消息将被放置在死信队列中。然而,它们只是从 In 队列中删除,而不是进入死信队列public class MyOtherService : AsmServiceBase{    public void Any(MyRequest request)    {        try        {            throw new InvalidOperationException("this is an invalid operation");        }        catch (Exception ex)        {            Console.Write("exceptions");            throw;        }    }}[Route("/api/myrequest", "POST")]public class MyRequest : HeliosRequestBase<MyResponse>{    public string Content { get; set; }}public class MyResponse : HeliosResponseBase{}这是 AppHost 中的代码,它将 MyRequest 消息路由到我的服务方法:RabbitMqServer mqServer = RabbitMqServerFactory                         .GetRabbitMqServer(m_ServiceDiscovery).Result;mqServer.RegisterHandler<MyRequest>(ExecuteMessage);mqServer.Start();有人可以解释一下我做错了什么吗?
查看完整描述

1 回答

?
LEATH

TA贡献1936条经验 获得超6个赞

编辑

如果您使用显式ReplyTo地址,则任何错误都将发送到该 ReplyTo 地址而不是 DLQ。


如果您的 Response DTO 具有ResponseStatus属性,则 Exception 将填充在 Response DTO 的 ResponseStatus 中,否则您可以使用通用ErrorResponseDTO读取异常信息,例如:


var requestMsg = new Message<ThrowVoid>(request)

{

    ReplyTo = $"mq:{request.GetType().Name}.replyto"

};

mqProducer.Publish(requestMsg);


var msg = mqClient.Get<ErrorResponse>(requestMsg.ReplyTo, null);

mqClient.Ack(msg);


msg.GetBody().ResponseStatus.ErrorCode //= InvalidOperationException

我无法仅使用正常的 ServiceStack 类来重现此问题,如在所有 MQ 服务器中按预期工作的提交所见。


我在下面提取了使用ServiceStack 的 RabbitMQ 服务器的代码:


public class ThrowVoid

{

    public string Content { get; set; }

}


public class TestMqService : Service

{

    public void Any(ThrowVoid request)

    {

        throw new InvalidOperationException("this is an invalid operation");

    }

}


public class AppHost : AppSelfHostBase

{

     public AppHost(Func<IMessageService> createMqServerFn)

        : base(nameof(TestMqService), typeof(TestMqService).Assembly) {}


    public override void Configure(Container container)

    {

        var mqServer = new RabbitMqServer { RetryCount = 1 };

        container.Register<IMessageService>(c => mqServer);

        mqServer.RegisterHandler<ThrowVoid>(ExecuteMessage);


        AfterInitCallbacks.Add(appHost => mqServer.Start());

    }

}

发送消息的位置:


using (var mqFactory = appHost.TryResolve<IMessageFactory>())

{

    var request = new ThrowVoid { Content = "Test" };


    using (var mqProducer = mqFactory.CreateMessageProducer())

    using (var mqClient = mqFactory.CreateMessageQueueClient())

    {

        mqProducer.Publish(request);


        var msg = mqClient.Get<ThrowVoid>(QueueNames<ThrowVoid>.Dlq, null);

        mqClient.Ack(msg);


        Assert.That(msg.Error.ErrorCode, Is.EqualTo("InvalidOperationException"));

    }

}

无法确定您的问题是什么,因为很多实现隐藏在您自己的自定义类之后,但我建议从一个像上面这样的小型独立示例开始,该示例确实有效,然后慢慢添加您的自定义代码以识别是什么造成它。


尽管我建议不要使用继承来隐藏 DTO 中的属性,但 DTO 是用于定义服务合同的声明性模型,将它们的属性隐藏在继承之后会使阅读它的人更难确切知道每个服务接受和返回的内容。继承对于定义可重用的功能很有用,但 DTO 是声明性的,应该没有实现,所以你基本上是添加了不必要的耦合来隐藏显式的服务契约,从而更难通过查看服务契约来推断每个服务的作用.


查看完整回答
反对 回复 2021-11-21
  • 1 回答
  • 0 关注
  • 190 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信