我想使用在Spring集成中设置的API请求计时。响应时间应作为消息头添加,以便可以在下游进行审核,并与其他数据一起记录。
HTTP成功和错误响应都应该计时,例如,我想知道服务器发出500响应需要多长时间。我也已经在使用重试和断路器建议(因为我想要这个功能)。
我已经写了一个定制建议(来自
reading the docs
)并添加到我的:
public class RequestResponseTimeInterceptor extends AbstractRequestHandlerAdvice {
private static final Logger LOG = Logger.getLogger(RequestResponseTimeInterceptor.class);
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
long before = System.currentTimeMillis();
try {
Object result = callback.execute();
long after = System.currentTimeMillis();
message = MessageBuilder.fromMessage(message).setHeader("requestResponseTime", after - before).build();
return result;
}
catch (MessageHandlingException e) {
long after = System.currentTimeMillis();
Message modifiedFailedMessage = MessageBuilder.fromMessage(e.getFailedMessage()).setHeader("requestResponseTime", after - before).build();
throw new MessageHandlingException(modifiedFailedMessage, e.getMessage(), e.getCause());
}
}
<bean id="calculationRetry" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice"/>
<bean id="calculationCircuitBreaker" class="org.springframework.integration.handler.advice.RequestHandlerCircuitBreakerAdvice"/>
<bean id="timer" class="com.integration.audit.RequestResponseTimeInterceptor"/>
<int-http:request-handler-advice-chain>
<ref bean="timer"/>
<ref bean="calculationRetry"/>
<ref bean="calculationCircuitBreaker"/>
</int-http:request-handler-advice-chain>
它通过回调执行之间的计时来工作。我有一个问题,失败的HTTP响应(例如HTTP 500)被包装在MessageHandlingException中(在Spring集成中,根据设计),这会阻止其余的建议完成响应并计时。
我在代码示例中解决了这个问题,捕获异常,将响应时间添加为消息头,重新创建异常并抛出它(因此它会被我的错误通道拾取)。这似乎效果不错,但感觉这不是最好的解决方案。它还将乘以任何重试(根据我的重试建议)的完整持续时间,而不是上次重试的时间。
有没有更好的方法来计时HTTP请求/响应,这样可以很好地处理现有的重试建议和失败的HTTP响应代码?
感谢您的反馈!
编辑:基于Artem的信息。
请求处理程序建议链中建议的顺序很重要(毕竟它是一个有序链)。因此,将“计时器”放在链的末尾意味着它只对请求/响应进行计时,而不是多次重试或断路。
我根据Artem的评论更新了建议,所以现在它实际上返回了一条消息。然后,我可以根据需要在管道下游读取新的“requestResponseTime”头。
以下是新代码:
public class RequestResponseTimeInterceptor extends AbstractRequestHandlerAdvice {
private static final Logger LOG = Logger.getLogger(RequestResponseTimeInterceptor.class);
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> requestMessage) throws Exception {
long before = System.currentTimeMillis();
try {
Object result = callback.execute();
long after = System.currentTimeMillis();
Message<?> responseMessage = (Message<?>) result;
return MessageBuilder.withPayload(responseMessage.getPayload())
.setHeader(MessageHeaderConstants.REQUEST_RESPONSE_TIME, after - before).build();
}
catch (MessageHandlingException e) {
//Catch HTTP errors (e.g. 500s) so we can also time the response
long after = System.currentTimeMillis();
Message modifiedFailedMessage = MessageBuilder.fromMessage(e.getFailedMessage()).setHeader(MessageHeaderConstants.REQUEST_RESPONSE_TIME, after - before).build();
//rethrow new exception for error handling
throw new MessageHandlingException(modifiedFailedMessage, e.getMessage(), e.getCause());
}
}
<int-http:request-handler-advice-chain>
<ref bean="calculationCircuitBreaker"/>
<ref bean="calculationRetry"/>
<ref bean="timer"/>
</int-http:request-handler-advice-chain>