簡體   English   中英

ServiceStack.Redis:配置使請求和響應類/dto相同class?

[英]ServiceStack.Redis: Configure so that the request and response class/dto is the same class?

不久前我一直在使用 ServiceStack,我很清楚基於消息的 API 設計是首選,這是我在一些基於 REST 的 API 中使用的東西。

我現在正在研究 Redis / MQ 庫,並且一如既往地享受 ServiceStack 的結構和功能。 但是,我正在考慮用 MQ 服務器替換一些遺留通信代碼,並 測試了一些 SS 示例,並且效果很好。

但是,我正在使用的一些遺留代碼使用相同的 class 用於傳出請求和響應,就像發送GetSomething一樣,並且回復是相同 class GetSomething的實例,但具有像GetSomething.Result這樣包含回復的屬性/結果。

由於我想直接替換當前的通信 model,因此我查看了是否可以“開箱即用”支持這種方案,但我並沒有真正找到任何解決這個問題的方法。 當我在具有處理程序的消費者中這樣的事情時:

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

以及想要回復的發布者:

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

發生的情況是發布者立即獲取請求,並且它永遠不會到達消費者。 如果我在 Publisher 中刪除了回復的偵聽器,它會到達消費者,但是當消費者使用相同的 DTO GetSomething回復時,它會陷入一個永恆的循環,因為我認為回復是放在同一個MQ 隊列。

有沒有使用 ServiceStack 解決這個問題的聰明方法?

我對可能的解決方法有一些想法,但我想知道這是否可以以更好、更智能的方式解決。

我只是想分享一種解決方法,它可能不是最漂亮的,但似乎有效。 如果有更好的方法來做到這一點,我仍然很感興趣。

出版商:

發布者將 RequestFilter 分配給 RedisMqServer,並在該方法中修改.Body ,將包裝器替換為實際請求。

Publisher 然后為響應包裝器 class 調用.RegisterHandler一次,然后按預期為每個實際/真實 Handler 調用。 這將導致調用正確的服務處理程序:

    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;
    }
}

ServiceStack MQ 消息工作流在文檔中定義:

ServiceStack MQ 消息工作流

並解釋在以下情況下會發生什么:

沒有響應的消息被發送到“.outq”主題

帶有響應的消息發布到 Response.inq

來自帶有 ReplyTo 的消息的響應發布到該地址

重試有異常的消息,然后發布到.dlq dead-letter-queue

因此,返回請求 DTO 會將其放入請求 DTO 的 INQ 中,該請求 DTO 將由注冊處理它的處理程序執行,在這種情況下,它恰好是它自己,因此是循環。 在 Redis MQ 服務返回nullvoid將其發布到 Redis 的瞬態/滾動響應 DTO.outq。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM