Я создал простой пример, чтобы узнать о повторных попытках и советах. Вот пример конфигурации:Повторные попытки и советы по интеграции весов
@Configuration
@EnableIntegration
@IntegrationComponentScan
@ComponentScan
public class SimpleConfiguration2 {
@Bean
public DirectChannel requestChannel() {
return new DirectChannel();
}
@Bean
public DirectChannel aChannel() {
return new DirectChannel();
}
@Bean
public DirectChannel retryLaterChannel() {
return new DirectChannel();
}
@Bean
public DirectChannel tapChannel() {
return new DirectChannel();
}
@Bean
public DirectChannel endChannel() {
return new DirectChannel();
}
@Bean
public ExceptionThrowingTransformer exceptionThrowingTransformer() {
return new ExceptionThrowingTransformer();
}
@Bean
public IntegrationFlow initFlow() {
return IntegrationFlows.from(requestChannel())
.gateway(aChannel(), e -> e.advice(retryAdvice())
.errorChannel(retryLaterChannel()))
.get();
}
@Bean
public Advice retryAdvice() {
final RequestHandlerRetryAdvice advice = new RequestHandlerRetryAdvice();
advice.setRetryTemplate(retryTemplate());
return advice;
}
@Bean
public RetryTemplate retryTemplate() {
final RetryTemplate ret = new RetryTemplate();
ret.setRetryPolicy(retryPolicy());
ret.setThrowLastExceptionOnExhausted(false);
return ret;
}
@Bean
public RetryPolicy retryPolicy() {
final Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>() {{
put(RuntimeException.class, true);
}
private static final long serialVersionUID = -1L;
};
final RetryPolicy ret = new SimpleRetryPolicy(3, map, true);
return ret;
}
@Bean
public IntegrationFlow aChannelFlow() {
return IntegrationFlows.from(aChannel())
.transform("C: "::concat)
.transform(exceptionThrowingTransformer())
.channel(endChannel())
.get();
}
@Bean
public IntegrationFlow endFlow() {
return IntegrationFlows.from(endChannel())
.handle(String.class, (p, h) -> p)
.get();
}
@Bean
public IntegrationFlow retryLaterFlow() {
return IntegrationFlows.from(retryLaterChannel())
.wireTap(tapChannel())
// .bridge(null)
// .handle(String.class, (p, h) -> p)
.get();
}
@Bean
public IntegrationFlow tapFlow() {
return IntegrationFlows.from(tapChannel())
.handle(m -> System.err.println("tap [" + Thread.currentThread().getName() + "] " + m.getPayload()))
.get();
}
}
и вот ExceptionThrowingTransformer:
public class ExceptionThrowingTransformer implements GenericTransformer<String, String> {
@Override
public String transform(final String source) {
printAndThrow();
return Thread.currentThread().getName() + " " + source;
}
private void printAndThrow() {
if(numFail > 0) {
numFail--;
final String msg = numFail > 0 ? " will fail " + numFail + " more times"
: "last failure";
System.out.println(Thread.currentThread().getName() + " ExceptionThrowingTransformer " + msg);
throw new RuntimeException();
}
}
private static int numFail = 2;
}
Вот тестовый модуль:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SimpleConfiguration2.class)
public class DependenciesApplicationTests {
@Test
public void t1() {
System.out.println(gw.echo("MSG1"));
}
@Autowired
private EchoGateway gw;
}
и эхо-шлюз:
@MessagingGateway(defaultReplyTimeout=600)
public interface EchoGateway {
@Gateway(requestChannel = "requestChannel")
String echo(String message);
}
Вопрос 1: Если я запускаю код, как есть, для ввода «msg1», который получает помещенный на requestChannel, я получаю следующий результат:
main ExceptionThrowingTransformer will fail 1 more times
tap [main] org.springframework.integration.transformer.MessageTransformationException: ; nested exception is org.springframework.messaging.MessageHandlingException: ; nested exception is java.lang.RuntimeException
main ExceptionThrowingTransformer last failure
tap [main] org.springframework.integration.transformer.MessageTransformationException: ; nested exception is org.springframework.messaging.MessageHandlingException: ; nested exception is java.lang.RuntimeException
main C: MSG1
тогда как я ожидал бы увидеть что-то вроде:
main ExceptionThrowingTransformer will fail 1 more times
main ExceptionThrowingTransformer last failure
main C: MSG1
повторение происходит, но все же исходное исключение распространяется на errorChannel, указанный в шлюзе initFlow. Есть ли способ предотвратить это?
Вопрос 2: Когда numFail изменяется на 3, к тому же выход, как в вопросе 1, исключение возвращается вызывающему:
org.springframework.messaging.MessagingException: failure occurred in error-handling flow; nested exception is org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application:-1.retryLaterChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
Если только первый комментарий в retryLaterFlow является раскомментирована, исключение брошено исключениеThrowingTransformer возвращается вызывающему. Почему это, учитывая, что retryTemplate имеет setThrowLastExceptionOnExhausted (false)?
Вопрос 3: Если только второй комментарий в retryLaterFlow является раскомментирована, выход выглядит следующим образом:
main ExceptionThrowingTransformer will fail 2 more times
tap [main] org.springframework.integration.transformer.MessageTransformationException: ; nested exception is org.springframework.messaging.MessageHandlingException: ; nested exception is java.lang.RuntimeException
org.springframework.integration.transformer.MessageTransformationException: ; nested exception is org.springframework.messaging.MessageHandlingException: ; nested exception is java.lang.RuntimeException
Почему не повторная попытка вступить в силу? (Ответ на вопрос 1 также может ответить на этот вопрос)