При стандартных Spring-прокси внутренний вызов notifyAboutUpdatedUser не активирует @Async. Метод выполняется синхронно; после выноса в отдельный бин появится риск чтения до commit обновления.
Асинхронное изменение данных пользователя
При стандартных Spring-прокси внутренний вызов notifyAboutUpdatedUser не активирует @Async. Метод выполняется синхронно; после выноса в отдельный бин появится риск чтения до commit обновления.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Провести ревью класса UserServiceImpl, выявив возможные проблемы в реализации асинхронного обновления и последующего сохранения данных о пользователе.
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final NotificationService notificationService;
@Override
@Transactional
public void updateUser(UUID id) {
User user = userRepository.findById(id);
user.setName(RandomStringUtils.random(6));
userRepository.save(user);
notifyAboutUpdatedUser(id);
}
@Override
@Async
public void notifyAboutUpdatedUser(UUID id) {
User user = userRepository.findById(id);
NotificationInfo notificationInfo = notificationService.notify(user);
user.setNotifyInfoMessage(notificationInfo.getMessage());
userRepository.save(user);
}
}
Ответ
При стандартных Spring-прокси внутренний вызов notifyAboutUpdatedUser не активирует @Async. Метод выполняется синхронно; после выноса в отдельный бин появится риск чтения до commit обновления.
Надёжнее записать outbox-событие вместе с изменением пользователя, а обработку уведомления выполнить отдельным worker с идемпотентностью и своей короткой транзакцией сохранения результата. Вариант события after-commit устраняет гонку чтения, но без постоянной очереди может потеряться при падении процесса. Для стандартного Spring Data findById возвращает Optional<User>, требуется обработать отсутствие. Конкурентное сохранение сущности после уведомления не должно перезаписывать более новые поля — нужен version check или адресное обновление. Ошибки асинхронного void-метода также требуют наблюдаемости.