Обработка событий CDI при сбое и перезапуске сервера - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь сохранить элемент в БД, используя службу, и запускаю сообщение JMS для последующей службы, чтобы забрать сохраненный элемент, чтобы он мог обработать его.Эта конкретная операция происходит в одной транзакции.Но из-за состояния гонки время от времени вторая служба не может получить соответствующий элемент, поскольку он еще не сохранен.

Мой вариант использования очень распространен, и на разных форумах обсуждается множество вопросов, связанных с этим.Одним из решений этой проблемы является использование событий CDI.Я попробовал то же самое и мог решить часть проблемы.Псевдокод выглядит следующим образом:

@Inject
@Transaction
private Event<Item> itemEvent;

public void handleItem(Item item) {
  //code to persist the item
  itemEvent.fire(item);
}

@Asynchronous
public void observeAfterTransactionCompletion(@Observes(during = TransactionPhase.AFTER_SUCCESS) @Transaction Item item) {
  //code to send JMS message to the second service
}

Моя единственная проблема - когда персистентность успешна и событие запускается, и непосредственно перед тем, как наблюдатель начинает обрабатывать событие, если сервер Jboss выходит из строя, вторая служба не будетполучать уведомление, поскольку сообщение JMS не будет отправлено.

Может ли контейнер CDI внутренне обработать этот сценарий, чтобы событие всегда вызывалось?Будет ли наблюдатель уведомлен о запуске сервера автоматически?Если нет, то как мне справиться с этим сценарием, чтобы мой подход был надежным?

ПРИМЕЧАНИЕ: Я уже опробовал подход повторной попытки во втором сервисе, пока сообщение не станет доступным.Также сохранение события в другой очереди - альтернативный подход, который кажется очень утомительным.В поисках разумного подхода.

ОБНОВЛЕНИЕ: Мой исходный код был написан таким образом, что постоянство и обмен сообщениями были в одной транзакции.Но это привело к потреблению сообщений второй службой до того, как даже первое сохранение службы было успешным, что привело к ошибке, поскольку вторая служба не смогла найти требуемые данные, которые еще должны быть сохранены.

ОБНОВЛЕНИЕ 2: Псевдокод первоначального подхода выглядит следующим образом: @TransactionAttribute(TransactionAttributeType.REQUIRED) public void processMessage() { // code to persist data to DB // code to publish JMS message to the consumer }

Даже при использовании xa-datasouce и фабрики xa-connection проблема все еще существует.

Ответы [ 2 ]

0 голосов
/ 20 июня 2019

События CDI не являются постоянными и, следовательно, они не запускаются повторно после перезапуска сервера.

Наконец, мы решили проблему, используя постоянство БД перед публикацией сообщения и разделив постоянство и публикацию на две разные транзакции. Однако нам необходимо самостоятельно обработать дублирование сообщений в случае ошибок публикации сообщений или перезапуска сервера до того, как публикация сообщений будет зафиксирована.

0 голосов
/ 24 января 2019

Один из подходов заключается в использовании транзакций XA.

И JMS, и ресурсы базы данных присоединяются к одной и той же транзакции, поэтому сообщение JMS запускается при фиксации, либо возникает ошибка при обновлении базы данных или при отправке сообщения JMS.откат всей операции.

Обратите внимание, что вам придется изменить определение источника данных, используйте xa-datasource, обновите конфигурацию фабрики соединений JMS, чтобы использовать xa, и что сеанс JMS также должен передаваться

 <!-- JMS connection factory configuration -->
 <pooled-connection-factory name="myCxFactory">
     <transaction mode="xa"/>
     [...]
 </pooled-connection-factory>

// JMS session creation (message producer)
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);

Обратите также внимание, что только транзакция по производству сообщений является частью транзакции, а не его потребление

...