Sobes.tech
Назад к вопросам
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 есть несколько проблем:

  1. Асинхронность и транзакция:

    • Внутри transactionTemplate.executeWithoutResult происходит асинхронный вызов через WebClient, но результат этого вызова никак не обрабатывается и не дожидается.
    • Это значит, что HTTP-запрос может быть прерван или не выполнен до завершения транзакции.
  2. Порядок операций:

    • Сначала вызывается interviewScoreMLService.compute(c) — предположительно синхронный вызов.
    • Затем формируется тело запроса и создаётся Mono, но он не подписывается и не выполняется.
    • Далее вызывается scoreRepository.saveScore(s); — сохранение происходит внутри транзакции.
  3. Отсутствие обработки исключений:

    • Если сериализация или вызов 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 вне транзакции.

Это обеспечит целостность данных и корректность внешних вызовов.