Назад к вопросам
Райффайзен
Senior
5
/** * Метод считает сколько очков заработал кандидат, * сохраняет результат в базу и кидает callback об этом во внешний сервис */ public void process(Candidate c) { transactionTemplate.executeWithoutResult(status -> { Score s = interviewScoreMLService.compute(c); String body = objectMapper.writeValueAsString(Map.of(c.getName(), s)); Mono<ResponseEntity<Void>> request = WebClient.create() .post() .body(BodyInserters.fromValue(body)) .retrieve() .toBodilessEntity(); scoreRepository.saveScore(s); }); }
Компании, где спрашивали
Ответ от нейросети
sobes.tech AI
В представленном методе process есть несколько проблем:
-
Асинхронность и транзакция:
- Внутри
transactionTemplate.executeWithoutResultпроисходит асинхронный вызов черезWebClient, но результат этого вызова никак не обрабатывается и не дожидается. - Это значит, что HTTP-запрос может быть прерван или не выполнен до завершения транзакции.
- Внутри
-
Порядок операций:
- Сначала вызывается
interviewScoreMLService.compute(c)— предположительно синхронный вызов. - Затем формируется тело запроса и создаётся Mono, но он не подписывается и не выполняется.
- Далее вызывается
scoreRepository.saveScore(s);— сохранение происходит внутри транзакции.
- Сначала вызывается
-
Отсутствие обработки исключений:
- Если сериализация или вызов WebClient выбросят исключение, транзакция может быть некорректно завершена.
Рекомендации по исправлению:
- Если нужно, чтобы HTTP-запрос был выполнен в рамках транзакции, стоит использовать синхронный вызов или дождаться завершения Mono.
- Если используется реактивный стек, лучше весь метод сделать реактивным и управлять транзакцией реактивно.
- В текущем виде нужно явно подписаться на Mono и обработать ошибки.
Пример исправленного фрагмента (с блокировкой на выполнение HTTP-запроса):
transactionTemplate.executeWithoutResult(status -> {
Score s = interviewScoreMLService.compute(c);
String body = objectMapper.writeValueAsString(Map.of(c.getName(), s));
WebClient.create()
.post()
.body(BodyInserters.fromValue(body))
.retrieve()
.toBodilessEntity()
.block(); // блокируем до завершения запроса
scoreRepository.saveScore(s);
});
Или, если хочется отделить сохранение от уведомления:
- Сначала сохранить результат в базе.
- Затем асинхронно отправить callback вне транзакции.
Это обеспечит целостность данных и корректность внешних вызовов.