servicestack.redis:配置请求和响应类/dto是同一个类?

c9x0cxw0  于 2021-06-09  发布在  Redis
关注(0)|答案(2)|浏览(399)

我很久以前就使用过servicestack,我很清楚基于消息的api设计是首选,这是我在一些基于rest的api中使用的。
我现在正在研究redis/mq库,并一如既往地享受servicestack的结构和功能。不过,我正在研究用mq服务器替换一些遗留通信代码,并测试了一些ss示例,效果很好。
但是,我正在处理的一些遗留代码对传出请求和响应使用相同的类,如 GetSomething 并且回复是同一类的示例 GetSomething ,但拥有像 GetSomething.Result 包含回复/结果的。
因为我想用一个临时替代当前的通信模型,所以我想看看这个场景是否可以“开箱即用”地得到支持,但我并没有找到解决这个问题的方法。当我在具有处理程序的消费者中这样做时:

mqHost.RegisterHandler<GetSomething>(base.ExecuteMessage);

出版商希望得到回复:

mqServer.RegisterHandler<GetSomething>(m => {...});

所发生的情况是,发布者会立即接收请求,而它永远不会到达消费者。如果我删除发布服务器中回复的侦听器,它将到达使用者,但是当使用者使用相同的dto进行回复时, GetSomething ,它陷入了一个永恒的循环中,因为我认为回复被放置在同一个mq队列中。
有没有一种聪明的方法可以使用servicestack来解决这个问题?
我对可能的解决办法有一些想法,但我想知道是否可以用更好更聪明的方法来解决这个问题。

4dbbbstv

4dbbbstv1#

我只想和大家分享一个解决方法,也许不是最漂亮的,但似乎很管用。我仍然有兴趣,如果有更好的方法来做这件事。
出版商:
发布者向redismqserver分配一个requestfilter,并在该方法中修改 .Body ,将 Package 器替换为实际请求。
出版商随后致电 .RegisterHandler 一次用于响应 Package 器类,然后按预期用于每个实际/实际处理程序。这将导致调用正确的服务处理程序:

public RedisClient(string name)
    {
        Name = name;
        redisFactory = new PooledRedisClientManager("localhost:6379");
        mqServer = new RedisMqServer(redisFactory, retryCount: 2);

        mqServer.RequestFilter = RequestFilter;

        // Response wrapper, ContainerResponse implements IProtocolContainer
        mqServer.RegisterHandler<ContainerResponse>(m => 
        {
            return m;
        });

        mqServer.RegisterHandler<GetSomething>(m =>
        {
            // m.Body is here an GetSomething
            return null;
        });
        mqServer.Start();
    }

    private ServiceStack.Messaging.IMessage RequestFilter(ServiceStack.Messaging.IMessage message)
    {
        if (message.Body is IProtocolContainer protocolContainer)
        {
            message.Body = protocolContainer.TheRequest;
        }
        return message;
    }

    public void AddMessage<T>(T theRequest) where T : CoreRequest
    {
        using (var mqClient = mqServer.CreateMessageQueueClient())
        {
            mqClient.Publish(new ContainerRequest(theRequest));
        }
    }
}

消费者:
同样的原则也适用于消费者:

public override void Configure(Container container)
    {
        container.Register(new ConsumerInfo() { Name = ServiceName });

        var redisFactory = new PooledRedisClientManager("localhost:6379");
        container.Register<IRedisClientsManager>(redisFactory);
        var mqHost = new RedisMqServer(redisFactory, retryCount: 2);

        mqHost.RequestFilter = RequestFilter;
        mqHost.ResponseFilter = ResponseFilter;

        mqHost.RegisterHandler<ContainerRequest>(base.ExecuteMessage);
        mqHost.RegisterHandler<GetSomething>(base.ExecuteMessage);
        mqHost.Start();
    }

    private object ResponseFilter(object arg)
    {
        return new ContainerResponse(arg as CoreRequest);
    }

    private ServiceStack.Messaging.IMessage RequestFilter(ServiceStack.Messaging.IMessage message)
    {
        if (message.Body is IProtocolContainer protocolContainer)
        {
            System.Diagnostics.Debug.WriteLine($"\tReplaced Body with {protocolContainer.TheRequest.GetType().Name}");
            message.Body = protocolContainer.TheRequest;
        }
        return message;
    }
}
9avjhtql

9avjhtql2#

servicestack mq消息工作流在文档中定义:

并解释了以下情况:

没有响应的邮件将发送到“.outq”主题

带有响应的消息将发布到response.inq

带有replyto的邮件的响应将发布到该地址

带异常的消息将重新尝试,然后发布到.dlq死信队列

因此,返回请求dto将其放入该请求dto的inq中,该请求dto将由注册来处理它的处理程序执行,在本例中,该处理程序恰好是自身,因此是循环。在redis mq服务中返回 null 或者 void 将其发布到redis的 transient /滚动响应dto.outq。

相关问题