Request/Reply 说明

Request/Reply explanation

我想了解 request/reply 模式是如何在 ServiceStack/MQServers

中实现的

假设来自 wiki

的用例
mqClient.Publish(new Hello { Name = "World" });

var responseMsg = mqClient.Get<HelloResponse>(QueueNames<HelloResponse>.In);
mqClient.Ack(responseMsg);
responseMsg.GetBody().Result //= Hello, World!

假设代码片段已在 IIS 托管的 Web 应用程序中的服务方法中调用

// web api - IIS hosts the service
public class WebRequestService : Service
{
    public IMessageService MessageService { get; set; }

    public object Any(MyWebRequest request)
    {
        using (var mqClient = MessageService.CreateMessageQueueClient())
        {
            var id = Guid.NewGuid().ToString();

            mqClient.Publish(new Hello { Id = id });
            var msgCopy = mqClient.Get<HelloResponse>(QueueNames<HelloResponse>.In);

            mqClient.Ack(msgCopy);
            var response = msgCopy.GetBody();
            Logger.DebugFormat("Request for '{0}' replied '{1}'.", id, response.Result);

        }

        return new MyWebRequestResponse
        {
            Result = "result"
        };
    }
}

Publish 方法将 Hello 请求发送到托管 HelloService 的中间层

// middletier - winservice hosts the service
public class HelloService : Service
{
    public object Any(Hello req)
    {
        return new HelloResponse
        {
            Result = req.Id
        };
    }
}

由于webapi/WebRequestService收到多个并发请求,如何实现"mqClient.Get"在Publish调用后收到相关Hello Request发出的响应?换句话说,在这个虚拟样本中,我如何确定 Hello.Id(通过 Publish 方法发送)与 HelloResponse.Result(通过 mqClient.Get 接收)相匹配? 如何确保与发布的请求及其回复的相关性? 如何防止 mqClient.Get 偷看与上一行代码中发布的消息无关的消息?

目前我想出的唯一方法是使用 replyTo 选项,以便为每个 WebApi 请求创建一个队列,但我不认为这是一个选项

var uid = Guid.NewGuid().ToString();
string replyToMq = "mq:Hello.replyto." + uid;
mqClient.Publish(new Message<Hello>( new Hello { Id = id })
{
    ReplyTo = replyToMq
});
var msgCopy = mqClient.Get<HelloResponse>(replyToMq);

如果您想获得与特定请求相关的响应,您需要specify a ReplyTo address,例如:

const string replyToMq = mqClient.GetTempQueueName();
mqClient.Publish(new Message<Hello>(new Hello { Name = "World" }) {
    ReplyTo = replyToMq
});

IMessage<HelloResponse> responseMsg = mqClient.Get<HelloResponse>(replyToMq);
mqClient.Ack(responseMsg);
responseMsg.GetBody().Result //= Hello, World!

您不需要为长运行(无状态)进程指定 ReplyTo,这些进程通常可以处理任何响应,即在每个请求完成后执行任何额外的处理。