Асинхронное изменение данных пользователя

При стандартных 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-метода также требуют наблюдаемости.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее