Search code examples
redisservicestackmqservicestack.redis

ServiceStack RedisMessageQueueClient: Errors are not returned to the ReplyTo address, nor is the RetryAttempts used?


I am using the RedisMessageQueueClient as can be seen here:

    public TResponse SendSync<TRequest, TResponse>(TRequest request, int? timeoutMilliseconds = null)
        where TRequest : CoreRequest 
        where TResponse : CoreRequest
    {
        IMessage responseMessage = null;
        using (var mqClient = MqClientFactory.Instance.CreateMessageQueueClient())
        {
            // mqClient is ServiceStack.Messaging.RedisMessageQueueClient

            var uniqueCallbackQ = $"mq:c1:{request.GetType().Name}:{Guid.NewGuid():N}";
            var clientMsg = new Message<TRequest>(request)
            {
                ReplyTo = uniqueCallbackQ,
                RetryAttempts = 0
            };
    
            mqClient.Publish(clientMsg);
    
            TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds.HasValue ? timeoutMilliseconds.Value : 120000);
    
            //Blocks thread on client until reply message is received
            responseMessage = mqClient.Get<TResponse>(uniqueCallbackQ, timeout);
    
            if(responseMessage?.Body == null)
            {
                throw new TimeoutException($"Request {request.GetType().Name} from {Assembly.GetEntryAssembly().GetName().Name} has timed out!");
            }
    
        }
        return responseMessage?.Body as TResponse;
    }

for some reason in my code, an error is produced (this is what I am actually trying to find), and according to this SO post, that error should be returned to the ReplyTo address:

If you're using an explicit ReplyTo address any Errors will be sent to that ReplyTo address instead of the DLQ.

In this case, I am using the ReplyTo, like this:

ReplyTo is set, as well as the RetryAttempts

However, when I browse Redis, I see that the request has ended in in a DLQ, but not the ReplyTo address. In the image below, we see that:

  1. The ReplyTo address is set and it is the same as in the code above
  2. The RetryAttempts is 0 in code, but 2 in the DQL dump; I also see that the failed request is resent 2 more times. The MqServer is created using _mqServer = new RedisMqServer(_redisClientManager, retryCount: 2), but I expected that I could override this, using the code above? I also changed it to _mqServer = new RedisMqServer(_redisClientManager, retryCount: 0), but it still retried twice.

enter image description here

.NET 5.0, ServiceStack.Redis.Core 5.10.4, Visual Studio 2019


Solution

  • This is still the case where failed Error Responses are sent to the ReplyMq:

    using (var mqFactory = appHost.TryResolve<IMessageFactory>())
    {
        var request = new ThrowGenericError { Id = 1 };
    
        using (var mqProducer = mqFactory.CreateMessageProducer())
        using (var mqClient = mqFactory.CreateMessageQueueClient())
        {
            var requestMsg = new Message<ThrowGenericError>(request)
            {
                ReplyTo = $"mq:{request.GetType().Name}.replyto"
            };
            mqProducer.Publish(requestMsg);
    
            var msg = mqClient.Get<ErrorResponse>(requestMsg.ReplyTo, null);
            mqClient.Ack(msg);
    
            Assert.That(msg.GetBody().ResponseStatus.ErrorCode, Is.EqualTo("ArgumentException"));
        }
    }
    

    Failed responses are sent immediately to ReplyTo, i.e. they're not retried so it's not clear where your DLQ messages are coming from.