在 Spring 集成应用程序中,是否可以在链外测试 Spring 重试机制?
In Spring Integration app, Is it possible to test a Spring Retry mechanism outside of chain?
我继承了一个 Spring 集成项目,其中包含 Spring 重试。我不确定它是否已经过测试,也没有单独的测试。所以我试着用一个简单的场景来练习它。
通过模拟 RestTemplate exchange
方法,我希望能够测试重试逻辑。我可以得到我想要抛出的异常,但它只发生一次 - 没有重试。
重试建议的 XML 在这里(retry-advice-context.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="retryAdvice" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice" >
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="${retry.initialInterval}"/>
<property name="maxInterval" value="${retry.maxInterval}"/>
<property name="multiplier" value="${retry.multiplier}"/>
</bean>
</property>
<property name="retryPolicy">
<bean class="com.reachlocal.mediapublishing.shim.integration.retry.CustomRetryPolicy">
<constructor-arg name="maxAttempts" value="${retry.maxAttempts}" />
<constructor-arg name="retryableExceptions" ref="retryableExceptions" />
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="errorChannel" />
</bean>
</property>
</bean>
<util:map id="retryableExceptions" map-class="java.util.HashMap" >
<entry key="java.net.SocketException" value="true" />
<entry key="com.examplel.ConnectionException" value="true" />
<entry key="com.example.CustomException" value="true" />
</util:map>
</beans>
这是一段 SI 处理文件:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<import resource="retry-advice-context.xml"/>
<int:channel id="channel1">
</int:channel>
<int:header-value-router id="commandTypeRouter" input-channel="commandChannel" <---DEFINED IN MASTER FILE
header-name="commandType" resolution-required="true">
<int:mapping value="COMMAND_1" channel="channel1"/>
</int:header-value-router>
<int:chain id="command1Chain" input-channel="channel1" output-channel="commandProcessed">
<int:header-enricher>
<int:error-channel ref="errorChannel" />
</int:header-enricher>
<int:service-activator ref="eventDataWriter" method = "addEventStart"/>
<int:service-activator ref="accountProcessor" method="processAccount">
<int:request-handler-advice-chain><ref bean="retryAdvice" /></int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
</beans>
所以重试 bean retryAdvice
是不同链的一部分。链还有很多,所以我只想能够检查服务层的重试逻辑。代码中的任何地方都没有重试注释(不知道是否需要)。
几个问题:
- 我可以从服务层测试重试功能还是需要执行整个链?
- 是否缺少重试机制所需的任何内容(注释,其他XML)?
顺便说一句,这是使用 SI 4.1.3。
谢谢。
更新 1:
设法在我的环境中获得 Gary 的项目 运行。之后,我将 retry-advice-context.xml
文件添加到主 SI xml 中。我将地图更改为仅包含 RuntimeException
。日志语句显示 ExponentialBackoffPolicy
语句。我还收到了 RetryTemplate
调试日志语句。
有了更多的理解,我将其中的内容翻译成我正在使用的真实代码,并取得了更大的成功。我收到了我的异常发生并将重试最多 3 次的日志语句。
不幸的是我得到的是:
17:29:26.154 DEBUG [task-scheduler-2][org.springframework.retry.support.RetryTemplate] Checking for rethrow: count=1
17:29:26.155 DEBUG [task-scheduler-2][org.springframework.retry.support.RetryTemplate] Retry failed last attempt: count=1
所以它最初知道它应该最多重试 3 次。但随后它声明它在 1 次重试后进行了最后一次尝试。
在 Gary 的工作代码中,调试语句将显示 Retry: count=2
等...用于下一次连续尝试。
在重试期间,Spock 测试代码中有一个 sleep
语句。我把时间加长和缩短都没有改变。
将继续尝试并通过重试代码进行调试,以了解为什么它在第一次重试时停止。
您不需要任何额外的注释或 XML。
如果您给链和服务 id
属性,您可以独立测试处理程序...
<int:chain id="myChain" input-channel="foo">
<int:transformer expression="payload" />
<int:service-activator id="myService" ref="bar">
<int:request-handler-advice-chain>
<int:ref bean="retry" />
</int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
<bean id="retry" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice" />
<bean id="bar" class="com.example.Bar" />
Bar
正在...
public class Bar {
private int count;
public void bar(String in) {
System.out.println(in);
if (count++ < 2) {
throw new RuntimeException("foo");
}
}
}
测试:
public class So39604931ApplicationTests {
@Autowired
@Qualifier("myChain$child.myService.handler")
public MessageHandler handler;
@Test
public void test() {
handler.handleMessage(new GenericMessage<>("foo"));
}
}
结果:
foo
foo
foo
您还应该为 org.springframework.retry
打开调试日志记录以查看重试行为。
08:51:16.897 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
foo
08:51:16.902 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
08:51:16.902 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
foo
08:51:16.903 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
08:51:16.903 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
foo
我继承了一个 Spring 集成项目,其中包含 Spring 重试。我不确定它是否已经过测试,也没有单独的测试。所以我试着用一个简单的场景来练习它。
通过模拟 RestTemplate exchange
方法,我希望能够测试重试逻辑。我可以得到我想要抛出的异常,但它只发生一次 - 没有重试。
重试建议的 XML 在这里(retry-advice-context.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="retryAdvice" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice" >
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="${retry.initialInterval}"/>
<property name="maxInterval" value="${retry.maxInterval}"/>
<property name="multiplier" value="${retry.multiplier}"/>
</bean>
</property>
<property name="retryPolicy">
<bean class="com.reachlocal.mediapublishing.shim.integration.retry.CustomRetryPolicy">
<constructor-arg name="maxAttempts" value="${retry.maxAttempts}" />
<constructor-arg name="retryableExceptions" ref="retryableExceptions" />
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="errorChannel" />
</bean>
</property>
</bean>
<util:map id="retryableExceptions" map-class="java.util.HashMap" >
<entry key="java.net.SocketException" value="true" />
<entry key="com.examplel.ConnectionException" value="true" />
<entry key="com.example.CustomException" value="true" />
</util:map>
</beans>
这是一段 SI 处理文件:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<import resource="retry-advice-context.xml"/>
<int:channel id="channel1">
</int:channel>
<int:header-value-router id="commandTypeRouter" input-channel="commandChannel" <---DEFINED IN MASTER FILE
header-name="commandType" resolution-required="true">
<int:mapping value="COMMAND_1" channel="channel1"/>
</int:header-value-router>
<int:chain id="command1Chain" input-channel="channel1" output-channel="commandProcessed">
<int:header-enricher>
<int:error-channel ref="errorChannel" />
</int:header-enricher>
<int:service-activator ref="eventDataWriter" method = "addEventStart"/>
<int:service-activator ref="accountProcessor" method="processAccount">
<int:request-handler-advice-chain><ref bean="retryAdvice" /></int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
</beans>
所以重试 bean retryAdvice
是不同链的一部分。链还有很多,所以我只想能够检查服务层的重试逻辑。代码中的任何地方都没有重试注释(不知道是否需要)。
几个问题:
- 我可以从服务层测试重试功能还是需要执行整个链?
- 是否缺少重试机制所需的任何内容(注释,其他XML)?
顺便说一句,这是使用 SI 4.1.3。
谢谢。
更新 1:
设法在我的环境中获得 Gary 的项目 运行。之后,我将 retry-advice-context.xml
文件添加到主 SI xml 中。我将地图更改为仅包含 RuntimeException
。日志语句显示 ExponentialBackoffPolicy
语句。我还收到了 RetryTemplate
调试日志语句。
有了更多的理解,我将其中的内容翻译成我正在使用的真实代码,并取得了更大的成功。我收到了我的异常发生并将重试最多 3 次的日志语句。
不幸的是我得到的是:
17:29:26.154 DEBUG [task-scheduler-2][org.springframework.retry.support.RetryTemplate] Checking for rethrow: count=1
17:29:26.155 DEBUG [task-scheduler-2][org.springframework.retry.support.RetryTemplate] Retry failed last attempt: count=1
所以它最初知道它应该最多重试 3 次。但随后它声明它在 1 次重试后进行了最后一次尝试。
在 Gary 的工作代码中,调试语句将显示 Retry: count=2
等...用于下一次连续尝试。
在重试期间,Spock 测试代码中有一个 sleep
语句。我把时间加长和缩短都没有改变。
将继续尝试并通过重试代码进行调试,以了解为什么它在第一次重试时停止。
您不需要任何额外的注释或 XML。
如果您给链和服务 id
属性,您可以独立测试处理程序...
<int:chain id="myChain" input-channel="foo">
<int:transformer expression="payload" />
<int:service-activator id="myService" ref="bar">
<int:request-handler-advice-chain>
<int:ref bean="retry" />
</int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
<bean id="retry" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice" />
<bean id="bar" class="com.example.Bar" />
Bar
正在...
public class Bar {
private int count;
public void bar(String in) {
System.out.println(in);
if (count++ < 2) {
throw new RuntimeException("foo");
}
}
}
测试:
public class So39604931ApplicationTests {
@Autowired
@Qualifier("myChain$child.myService.handler")
public MessageHandler handler;
@Test
public void test() {
handler.handleMessage(new GenericMessage<>("foo"));
}
}
结果:
foo
foo
foo
您还应该为 org.springframework.retry
打开调试日志记录以查看重试行为。
08:51:16.897 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
foo
08:51:16.902 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
08:51:16.902 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
foo
08:51:16.903 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
08:51:16.903 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
foo