RED-6310: Moved code to create user-preferences to a separate class so that the calling code can handle a persistence exception

This commit is contained in:
Viktor Seifert 2023-03-07 18:32:33 +01:00
parent 643ffc8723
commit 45bd8e6003
2 changed files with 46 additions and 12 deletions

View File

@ -10,6 +10,8 @@ import java.util.stream.Collectors;
import javax.transaction.Transactional;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.notification.NotificationPreferencesEntity;
@ -18,15 +20,20 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.service.v1.api.model.notification.NotificationPreferences;
import com.iqser.red.service.persistence.service.v1.api.model.notification.NotificationType;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class NotificationPreferencesPersistenceService {
private final NotificationPreferencesRepository notificationPreferencesRepository;
NotificationPreferencesRepository notificationPreferencesRepository;
private final NotificationRepository notificationRepository;
NonThreadSafeNotificationPreferencesRepositoryWrapper notificationPreferencesRepositoryWrapper;
NotificationRepository notificationRepository;
@Transactional
@ -64,18 +71,17 @@ public class NotificationPreferencesPersistenceService {
}
@Transactional
// This method intentionally does not have a @Transactional annotation, since it needs to handle an underlying transaction exception.
public NotificationPreferencesEntity getOrCreateNotificationPreferences(String userId) {
return notificationPreferencesRepository.findByUserId(userId).orElseGet(() -> {
var notificationPreference = new NotificationPreferencesEntity();
notificationPreference.setUserId(userId);
notificationPreference.setEmailNotificationsEnabled(false);
notificationPreference.setInAppNotificationsEnabled(true);
notificationPreference.setInAppNotifications(Arrays.stream(NotificationType.values()).map(Enum::name).collect(Collectors.toList()));
return notificationPreferencesRepository.save(notificationPreference);
});
try {
// The method called here will fail if it is called concurrently (more than 1 thread), since it will always try to create
// the desired entity. But the exception only means, that the entity has been created by another thread.
// In that case we can just fetch the data from the db.
return notificationPreferencesRepositoryWrapper.getOrCreateNotificationPreferences(userId);
} catch (DataIntegrityViolationException ex) {
return notificationPreferencesRepository.getByUserId(userId);
}
}
@ -91,4 +97,29 @@ public class NotificationPreferencesPersistenceService {
return notificationPreferencesRepository.findAll();
}
@Component
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
private static class NonThreadSafeNotificationPreferencesRepositoryWrapper {
NotificationPreferencesRepository notificationPreferencesRepository;
@Transactional(Transactional.TxType.REQUIRES_NEW)
public NotificationPreferencesEntity getOrCreateNotificationPreferences(String userId) {
return notificationPreferencesRepository.findByUserId(userId).orElseGet(() -> {
var notificationPreference = new NotificationPreferencesEntity();
notificationPreference.setUserId(userId);
notificationPreference.setEmailNotificationsEnabled(false);
notificationPreference.setInAppNotificationsEnabled(true);
notificationPreference.setInAppNotifications(Arrays.stream(NotificationType.values()).map(Enum::name).collect(Collectors.toList()));
return notificationPreferencesRepository.save(notificationPreference);
});
}
}
}

View File

@ -11,6 +11,9 @@ public interface NotificationPreferencesRepository extends JpaRepository<Notific
Optional<NotificationPreferencesEntity> findByUserId(String userId);
NotificationPreferencesEntity getByUserId(String userId);
void deleteByUserId(String userId);
}