在ServiceStack Web服务项目中给出以下代码:
public object Post(LeadInformation request)
{
if (request == null) throw new ArgumentNullException("request");
try
{
var msgId = Guid.NewGuid();
var profiler = Profiler.Current;
using (profiler.Step("Direct Api LeadInformation POST {0}".Fmt(msgId)))
{
var domainRequest = Mapper.Map<Leads.ServiceModel.Api.DirectApi.LeadInformationInfo>(request);
LeadInformationResponse response;
using (var client = base.MessageFactory.CreateMessageQueueClient())
{
var replyToMq = client.GetTempQueueName();
using (profiler.Step("request message {0}".Fmt(msgId)))
{
var requestMsg = new Message<Leads.ServiceModel.Api.DirectApi.LeadInformationInfo>(domainRequest)
{
ReplyTo = replyToMq,
Id = msgId,
};
client.Publish<Leads.ServiceModel.Api.DirectApi.LeadInformationInfo>(requestMsg);
}
using (profiler.Step("response message {0}".Fmt(msgId)))
{
var timeOut = TimeSpan.FromMilliseconds(2000);
// IMessageQueueClient.Get sleeps the thread for 100ms, lets wait for a total of x seconds
var responseMsg = client.Get<Leads.ServiceModel.Api.DirectApi.LeadInformationInfoResponse>(replyToMq, timeOut);
var domainResponse = responseMsg.GetBody();
if (domainResponse.ResponseStatus != null)
{
client.Nak(responseMsg, false);
}
client.Ack(responseMsg);
response = Mapper.Map<LeadInformationResponse>(domainResponse);
}
}
return response;
}
}
catch (Exception exception)
{
_log.Error(exception);
throw;
}
}
托管ServiceStack的Windows服务(2个版本,相同结果):
版本1
在另一个进程中调用Web服务,该进程可能会死并返回null或异常
mqServer.RegisterHandler<LeadInformationInfo>(m =>
{
try
{
repository.SaveMessage(m as Message);
LeadInformationInfo response;
using (var client = new JsonServiceClient(settingsFactory.GetMasterSetting("ProcessorApi:baseUri")))
{
response = client.Post<LeadInformationInfo>(m.GetBody());
}
return response; // will cause RabbitMQ to hang if null
}
catch (Exception exception)
{
_log.Error("RegisterHandler<LeadInformationInfo>", exception);
throw;
}
}, 1);
版本2
调用正在进行中的服务
mqServer.RegisterHandler<LeadInformationInfo>(m =>
{
var db = container.Resolve<IRepository>();
db.SaveMessage(m as Message);
var response = ServiceController.ExecuteMessage(m);
return response; // will cause RabbitMQ to hang if null
}, 4);
你会注意到,如果你在处理过程中返回null来模拟NullReferenceException,那么RabbitMQ临时队列就会停留在&#39;运行&#39; state vs.&#39; idle&#39;,它处于挂起状态,如此图所示。
。
队列将无限期地保持这种状态,只有这样才能解决这种情况,即回收RabbitMQ Windows服务或托管过程,无论哪种方式在生产环境中都能很好地工作。我已尝试设置超时,但在这种情况下,这似乎并不像预期的那样有效。
如何从这个问题中可靠地恢复?
谢谢你, 斯蒂芬
答案 0 :(得分:2)
响应为null
时的行为,因为服务的典型响应类型未知,Request DTO is published to the .out MQ。
此行为还包括客户端ReplyTo
请求,但后来将其更改为in this commit以将请求DTO发布回客户端ReplyTo
MQ。
虽然此更改现在应该清理客户端创建的独占临时回复MQ,但这意味着只返回请求DTO ,而不是响应DTO 客户通常会期望。这些行为在这些null Response MQ Tests中可见,如果您的处理程序返回空响应DTO,则可以避免此行为。虽然正常行为适用于异常气泡,但可以在请求DLQ中发布。
将null
个回复发布回ReplyMQ的更改可以从 v4.0.37 + 获得,现在是available on MyGet。