Search code examples
c#redisstackexchange.redisservicestack.redis

How can I publish to a ServiceStack.Redis Message Queue using StackExchange.Redis?


I have existing ServiceStack services that I want to switch to StackExchange.Redis one at a time. This involves swapping out senders and eventually receivers. This question is about publishing from StackExchange.Redis to ServiceStack.Redis.

This is the simple publisher I put together in a console app to test out the concept.

namespace SEMQSender
{
    public class MessagePublisher
    {
        IConnectionMultiplexer _connectionMultiplexer;
        public MessagePublisher()
        {
            _connectionMultiplexer = ConnectionMultiplexer.Connect(new ConfigurationOptions()
            {
                EndPoints = {
                        {
                        "MyRedisServer"
                        }
                },
                DefaultDatabase = 0,
                AllowAdmin = true,
                SyncTimeout = 100000
            });
        }

        public void Run()
        {
            var request = new MyRequest()
            {
                Id = 27
            };
            PushServiceStackRequest(request);
        }

        public void PushServiceStackRequest<T>(T request)
        {
            var messageText = SerializeRequestAsServiceStackMessage(request);
            Push($"mq:{request.GetType().Name}.inq", messageText);
        }

        public string SerializeRequestAsServiceStackMessage<T>(T request)
        {
            var requestJson = JsonSerializer.Serialize(request);
            requestJson.Remove(0, 1);
            var serviceStackMessage = new ServiceStackMessage()
            {
                Id = Guid.NewGuid(),
                CreatedDate = DateTimeOffset.Now,
                Options = 1,
                Priority = 0,
                RetryAttempts = 0
            };
            var messageJson = JsonSerializer.Serialize(serviceStackMessage);
            var requestType = request.GetType();
            var sBuilder = new StringBuilder();
            sBuilder.AppendJoin('.', requestType.Namespace.Split('.').Take(2));
            var ns = sBuilder.ToString();
            var result = $"{messageJson.Remove(messageJson.Length - 1, 1)}, \"Body\":{{\"__type\":\"{requestType.FullName}, {ns}\",{requestJson.Remove(0, 1)}}}";
            return result;
        }

        public void Push(RedisKey queueName, RedisValue value)
        {
            _connectionMultiplexer.GetDatabase().ListRightPush(queueName, value);
        }
    }

    public class ServiceStackRedisMessage
    {
        public Guid Id { get; set; }
        public DateTimeOffset CreatedDate { get; set; }
        public int Priority { get; set; }
        public int RetryAttempts { get; set; }
        public int Options { get; set; }
    }
}

namespace MyServiceStackService.ServiceModel.MyService
{
    public class MyRequest
    {
        public int Id { get; set; }
    }
}

and this is an example of how our ServiceStack services subscribe to redis messages

    container.Register<IRedisClientsManager>(c => new RedisManagerPool(ConfigurationManager.AppSettings["Redis"]));
    container.Register<ICacheClient>(c => container.Resolve<IRedisClientsManager>().GetCacheClient());
    var mqHost = new RedisMqServer(container.Resolve<IRedisClientsManager>(), retryCount: 2);
    container.Register<IMessageService>(c => mqHost);

    mqHost.RegisterHandler<MyRequest>(this.ServiceController.ExecuteMessage);

    mqHost.Start();

As far as I can tell the Redis key and value is identical to what I would have generated if I published the message using ServiceStack, but something strange happens on the subscriber side. Messages are only picked up off of the queue when the service first starts up. All messages placed on the queue after that are left where they are until the service is restarted. Messages that are picked up have all expected data on the deserialized object.

Hopefully someone with more knowledge of StackExchange.Redis or ServiceStack.Redis can help with this. Just in case anyone is curious: We're switching to StackExchange.Redis so that we can make async calls to Redis, which ServiceStack.Redis does not support.


Solution

  • If you want to know what commands a client is sending you can use Redis's MONITOR debugging command from redis-cli which will let you see all commands issued to the redis-server in real-time.

    To mimic the Redis MQ Client you also need to publish the name of the queue to the Redis Pub/Sub Topic QueueNames.TopicIn (mq:topic:in) which notifies the Redis MQ Server that messages have been published to that MQ.