1. Введение
Иногда при вызове веб-службы мы можем быть заинтересованы в повторении операции в случае возникновения ошибки. Используя Spring Integration, мы можем достичь этой функциональности с помощью класса RequestHandlerRetryAdvice . Этот класс позволит нам повторить операцию определенное количество раз, прежде чем отказаться и вызвать исключение. Этот пост покажет вам, как этого добиться.
Тестовое приложение будет вызывать веб-сервис, и если оно не ответит, оно будет ждать в течение указанного времени и будет пытаться повторить его, пока не получит ответ или не достигнет предела повторных попыток. Если предел достигнут, неудавшийся запрос будет сохранен в базе данных. Главным образом, этот пост показывает пример следующего:
- Использование исходящего шлюза для вызова веб-службы
- Конфигурирование рекомендаций по повторным попыткам при необходимости повторить операцию
- MongoDB интеграция.
Исходный код приложения можно найти на github .
Вы также можете получить исходный код проекта веб-службы, который вызывается приложением на github .
2. Веб-сервис вызова
Вариант использования : клиент вызывает веб-сервис и получает ответ.
Запрос поступает в систему обмена сообщениями через шлюз «вход в систему». Затем он достигает исходящего шлюза, вызывает веб-сервис и ожидает ответа. После получения ответ отправляется в канал ответа.
Изображение выше является результатом этой конфигурации:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<context:component-scan base-package="xpadro.spring.integration" /><!-- Initial service request --><int:gateway id="systemEntry" default-request-channel="requestChannel" service-interface="xpadro.spring.integration.gateway.ClientService" /> <int:channel id="requestChannel"> <int:queue /></int:channel><int-ws:outbound-gateway id="marshallingGateway" request-channel="requestChannel" reply-channel="responseChannel" unmarshaller="marshaller"> <int:poller fixed-rate="500" /></int-ws:outbound-gateway><oxm:jaxb2-marshaller id="marshaller" contextPath="xpadro.spring.integration.types" /><!-- Service is running - Response received --><int:channel id="responseChannel" /><int:service-activator ref="clientServiceActivator" method="handleServiceResult" input-channel="responseChannel" /> |
К каналу ответа подключен активатор службы, который просто регистрирует результат.
TestInvocation.java: отправляет запрос на входной шлюз
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@ContextConfiguration({"classpath:xpadro/spring/integration/config/int-config.xml", "classpath:xpadro/spring/integration/config/mongodb-config.xml"})@RunWith(SpringJUnit4ClassRunner.class)public class TestInvocation { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private ClientService service; @Test public void testInvocation() throws InterruptedException, ExecutionException { logger.info("Initiating service request..."); ClientDataRequest request = new ClientDataRequest(); request.setClientId("123"); request.setProductId("XA-55"); request.setQuantity(new BigInteger("5")); service.invoke(request); logger.info("Doing other stuff..."); Thread.sleep(60000); }} |
При такой конфигурации, если вызов службы завершится неудачно, MessagingException будет сгенерирован и отправлен в канал ошибок. В следующем разделе мы добавим конфигурацию повторных попыток.
3. Добавление повторных рекомендаций
Вариант использования : первоначальный запрос не выполнен, поскольку служба не активна. Мы будем повторять операцию до тех пор, пока от службы не будет получен ответ.
В этом случае нам нужно добавить рекомендацию повтора в исходящий шлюз веб-службы:
|
01
02
03
04
05
06
07
08
09
10
11
|
<int-ws:outbound-gateway id="marshallingGateway" interceptor="clientInterceptor" request-channel="requestChannel" reply-channel="responseChannel" unmarshaller="marshaller"> <int:poller fixed-rate="500" /> <int-ws:request-handler-advice-chain> <ref bean="retryAdvice" /> </int-ws:request-handler-advice-chain></int-ws:outbound-gateway> |
Теперь исходящий шлюз веб-службы будет делегировать вызов рекомендации повторения, которая будет пытаться выполнить операцию столько раз, сколько указано, пока не получит ответ от службы. Давайте определим совет повторной попытки:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
<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.FixedBackOffPolicy"> <property name="backOffPeriod" value="4000" /> </bean> </property> <property name="retryPolicy"> <bean class="org.springframework.retry.policy.SimpleRetryPolicy"> <property name="maxAttempts" value="4" /> </bean> </property> </bean> </property></bean> |
Для достижения этой цели в совете используется RetryTemplate, предоставляемый проектом Spring Retry . Мы можем настроить его поведение путем определения политик отката и повторных попыток .
Политика отката : устанавливает интервал времени между каждой повторной попыткой. Более интересные типы:
- FixedBackOffPolicy : используется в нашем примере. Он будет ждать одинаковое количество времени между каждой повторной попыткой.
- ExponentialBackOffPolicy : начиная с определенного промежутка времени, он удваивает время при каждой повторной попытке. Вы можете изменить поведение по умолчанию, установив множитель.
Политика повторных попыток: определяет, сколько раз будет повторяться неудачная операция. Некоторые из типов:
- SimpleRetryPolicy : используется в нашем примере. Указывает предел попыток повторной попытки.
- ExceptionClassifierRetryPolicy : позволяет нам устанавливать различные maxAttempts в зависимости от вызванного исключения.
- TimeoutRetryPolicy : повторять попытки до истечения времени ожидания.
4. Не повезло, регистрация неудачного запроса
Вариант использования : служба не будет восстановлена, сохраняя запрос к базе данных.
Последняя часть конфигурации следующая:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<!-- Log failed invocation --><int:service-activator ref="clientServiceActivator" method="handleFailedInvocation" input-channel="errorChannel" output-channel="logChannel" /><int:channel id="logChannel" /><bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory"> <constructor-arg> <bean class="com.mongodb.Mongo"/> </constructor-arg> <constructor-arg value="test"/></bean><int-mongodb:outbound-channel-adapter id="mongodbAdapter" channel="logChannel" collection-name="failedRequests" mongodb-factory="mongoDbFactory" /> |
Активатор службы, подписанный на канал ошибок, извлечет сообщение об ошибке и отправит его исходящему адаптеру, который вставит его в базу данных mongoDB. Активатор службы:
|
1
2
3
4
|
public Message<?> handleFailedInvocation(MessagingException exception) { logger.info("Failed to succesfully invoke service. Logging to DB..."); return exception.getFailedMessage();} |
Если нам не удастся получить ответ от сервиса, запрос будет сохранен в базе данных:
6. Заключение
Мы узнали, как Spring Integration получает поддержку от проекта Spring Retry, чтобы добиться повторных попыток выполнения операций. Мы использовали цепочку int-ws: request-handler-advice-chain , но пространство имен ‘int’ также поддерживает этот элемент, чтобы добавить эту функциональность в другие типы конечных точек.


