Почему Amazon sqs не поддерживает транзакции? - PullRequest
0 голосов
/ 22 октября 2018

Весной Rabbitmq поддерживает транзакции.Однако Amazon sqs не поддерживает транзакции в Spring.

Извините.Я добавил еще немного контента.Я протестировал две очереди сообщений (rabbitmq, amazon sqs), как показано ниже весной.

Моя цель - логика обработки электронной почты пользователя в очереди для отправки сообщения о завершении регистрации, когда пользователь завершает регистрацию без исключения..

//rabbit mq configuration.class
@Bean
public ConnectionFactory rabbitConnectionFactory() {
    CachingConnectionFactory connectionFactory =
            new CachingConnectionFactory("localhost",5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    return connectionFactory;
}

@Bean
public SimpleMessageListenerContainer messageListenerContainer() {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(rabbitConnectionFactory());
    container.setQueueNames(queue);
   container.setMessageListener(exampleListener());
    container.setTransactionManager(platformTransactionManager);
    container.setChannelTransacted(true);
    return container;
}


@Bean
public RabbitTemplate producerRabbitTemplate() {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory());
    rabbitTemplate.setQueue(queue);
    rabbitTemplate.setMandatory(true);
    rabbitTemplate.isChannelTransacted();
    rabbitTemplate.setChannelTransacted(true);
    return rabbitTemplate;
}



//UserService.class
@Autowired
private final UserRepository userRepository;
@Autowired
private final RabbitTemplate rabbitTemplate;

@Transactional
public User createUser(final User user){
    rabbitTemplate.convertAndSend("spring-boot", user.getEmail()); // SignUp Completion email
    final User user = userRepository.save(user);
    if(true) throw new RuntimeException();
    return user;
}

Однако приведенная выше логика вызывает исключение runtimeException.

Rabbit mq не будет отправлять данные в очередь из-за транзакционной аннотации в Spring при возникновении исключения.

//amazon sqs configuration.class
@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSqs) {

//UserService.class
@Autowired
private final UserRepository userRepository;
@Autowired
private QueueMessagingTemplate messagingTemplate;


@Transactional
public User createUser(final User user){
    messagingTemplate.convertAndSend("spring-boot", user.getEmail()); // SignUp Completion email
    final User user = userRepository.save(user);
    if(true) throw new RuntimeException();
    return user;
}

Однако sqs отправит данные в очередь, даже если возникнет исключение.

Кто-нибудь знает, почему это так?

1 Ответ

0 голосов
/ 23 октября 2018

TLDR Как я могу решить эту проблему?

Не пытайтесь использовать транзакции для этого, придумайте какой-нибудь способ сделать систему в конечном итоге непротиворечивой.


Звучит так, будто вы хотите выполнить «queue.sendMessage» и «repository.save», как если бы они были транзакцией - либо обе были зафиксированы, либо ни одна не зафиксирована.Проблема в том, что «транзакция» на самом деле не транзакционная, даже в вашем примере с кроликом.

Рассмотрим основы работы транзакции:

  1. своего рода beginшаг, означающий, что следующие изменения являются частью транзакции
  2. изменения сделаны (но не видны читателям)
  3. своего рода commit шаг для атомарной фиксации изменений (делая их видимыми длячитатели)

Однако в вашем случае очередь и хранилище являются отдельными объектами, поддерживаемыми отдельными сетевыми ресурсами, которые не общаются друг с другом.В этом случае нет атомарного коммита.Без атомарного коммита вы не сможете получить истинную транзакцию.Он «работает» в вашей демонстрации, потому что исключение отделено от кода, который выполняет запись.

Рассмотрим этот случай, чтобы более наглядно проиллюстрировать:

@Transactional
public User createUser(final User user){
    messagingTemplate.convertAndSend("spring-boot", user.getEmail());
    final User user = userRepository.save(user);
    return user;
}
  • Когда шаг фиксацииДля этого необходимо сделать видимым как сообщение (в очереди), так и пользователя (в репо)
  • Для этого необходимо выполнить сетевой вызов как в очередь, так и в очередь.repo
    • тот факт, что эти два вызова являются источником проблемы
  • Если один из них удастся, а другой потерпит неудачу, вы окажетесь в несогласованном состоянии
    • Вы можете сказать, что «транзакции могут быть откатаны» - но откат может привести к другому сетевому вызову, который, конечно, может завершиться неудачей.

Существуют способы сделатьВ целом распределенная система транзакционная, но это очень сложная проблема .Часто гораздо проще и быстрее учесть временную несогласованность и создать механизмы, позволяющие в конечном итоге привести систему в соответствие.

...