请求int-http:outbound-gateway的响应延迟时间

时间:2018-02-21 00:08:52

标签: spring-integration

我想用一个在Spring Integration中设置的API请求。响应时间应作为消息头添加,以便可以在下游进行审计并与其他数据一起记录。

HTTP成功和错误响应都应该定时,例如我想知道服务器发出500响应需要多长时间。我也已经在使用Retry和CircuitBreaker建议(因为我想要这个功能)。

我已经写了一份自定义建议(来自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 Integration中,按设计),这会阻止其他建议完成并对响应进行计时。

我已经在代码示例中通过捕获异常,将响应时间添加为消息头,重新创建异常并抛出异常(因此它被我的错误通道拾取)解决了这个问题。这似乎工作正常 - 但感觉它不是最好的解决方案。它也是任何重试的完整持续时间(来自我的重试建议),而不是最后一次重试。

是否有更好的方法来定时HTTP请求/响应,它可以很好地与现有的重试建议和失败的HTTP响应代码一起使用?

感谢您的反馈!

修改:根据Artem的信息。

request-handler-advice-chain中的建议顺序很重要(毕竟它是一个有序的链)。所以把'计时器'#39;在链的末端意味着它只是请求/响应的次数,而不是多次重试或断路器。

我根据Artem的评论更新了建议,现在它实际上正在返回一条消息。然后,我可以阅读新的&#34; requestResponseTime&#34;根据需要在管道下游标题。

这是新代码:

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>

1 个答案:

答案 0 :(得分:1)

首先想一想你的计时器是否应该包含所有重试次数。对于打开断路器的超时计数而言,这对我来说似乎并不重要。我的意思是以不同的方式重新排序你的建议会更加现实:首先是电路,重试然后只有计时器。这样,您将只计算真实的http请求,并且不会通过打开的电路进入该部分。

关于您的例外问题。使用必需的标题重建消息肯定是可以的。为此,我们引入了RewriteEngine On RewriteCond %{QUERY_STRING} ^(.*)$ RewriteCond %{QUERY_STRING} !^command RewriteRule ^(.*) http://your.domain?command=$1&%1 [L] https://docs.spring.io/spring-integration/docs/latest-ga/reference/html/whats-new.html#_errormessagepublisher_and_errormessagestrategy

另一方面,请注意Spring Cloud Sleuth项目:https://cloud.spring.io/spring-cloud-sleuth/