Документация по
Axon содержит ошибки в описании нюансов между EventScheduler
и DeadlineManager
, а также в том, в каком сценарии вы должны использовать каждый из них. В испытании огнем я попытался использовать EventScheduler
в одном из немногих реализованных Saga
. Я понял, что он не запускает @EventSourcingHandler
на Aggregate, поэтому был вынужден перейти на DeadlineManager
. (Подсказка: это можно было бы лучше описать в документации)
Теперь первой задачей было настроить DeadlineManager без какого-либо понимания. Вот последний код, который я закончил:
@Configuration
public class AxonConfiguration {
@Bean
public DeadlineManager deadlineManager(
final Scheduler scheduler,
// Disregard "Could not autowire. No beans of 'AxonConfiguration' type found." complain from IntelliJ.
// This class is an @Configuration, which is a @Component by itself.
final org.axonframework.spring.config.AxonConfiguration configuration,
final TransactionManager transactionManager,
final Serializer serializer
) {
return QuartzDeadlineManager.builder()
.scheduler(scheduler)
.serializer(serializer)
.scopeAwareProvider(new ConfigurationScopeAwareProvider(configuration))
.transactionManager(transactionManager)
.build();
}
}
Как вы можете видеть, при использовании уважаемой среды IDE он жалуется, что AxonConfiguration не является Bean, поэтому вы должны жить с предупреждением вечно.
Когда я ввел DeadlineManager
в свой Saga
, я сделал следующее:
@Slf4j
@Saga
public class MySaga {
static final Long DELAY_INITIALIZE = 60L;
static final String INITIALIZE_DEADLINE_NAME = "MyInitialize";
@Autowired
private transient DeadlineManager deadlineManager;
@Autowired
private transient CommandGateway commandGateway;
private String scheduleName;
private String scheduleId;
@StartSaga
@SagaEventHandler(associationProperty = "correlationId")
protected void on(final ScheduleEvent event, @Timestamp final Instant eventInstant) {
final Instant timerInitialize = eventInstant.plus(Duration.ofSeconds(DELAY_INITIALIZE));
this.scheduleName = INITIALIZE_DEADLINE_NAME;
this.scheduleId = this.deadlineManager.schedule(
timerInitialize,
INITIALIZE_DEADLINE_NAME,
InitializeEvent.builder()
.id(event.getId())
.build()
);
}
@DeadlineHandler(deadlineName = INITIALIZE_DEADLINE_NAME)
protected void onDeadline(final InitializeEvent command) {
this.commandGateway.send(command);
}
// ...
}
Я абстрагировал нерелевантный код. Имейте в виду, что нигде в кодовой базе мы не изменяем экземпляр StdScheduler
, внедренный как зависимость Bean для DeadlineManager
.
Однако при выполнении моего кода я продолжаю получать следующее исключение:
2020-05-28 03:26:13.001 ERROR 1 --- [eduler_Worker-1] o.a.deadline.quartz.DeadlineJob : Exception occurred during processing a deadline job which will be retried [com.eblock.simulcast.bidding_engine_axon.auction_event.command.InitializeAuctionEvent]
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413) ~[hibernate-core-5.4.15.Final.jar!/:5.4.15.Final]
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1608) ~[hibernate-core-5.4.15.Final.jar!/:5.4.15.Final]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:409) ~[spring-orm-5.2.6.RELEASE.jar!/:5.2.6.RELEASE]
at com.sun.proxy.$Proxy175.executeUpdate(Unknown Source) ~[na:na]
at org.axonframework.modelling.saga.repository.jpa.JpaSagaStore.updateSaga(JpaSagaStore.java:272) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.modelling.saga.repository.AnnotatedSagaRepository.updateSaga(AnnotatedSagaRepository.java:208) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.modelling.saga.repository.AnnotatedSagaRepository.commit(AnnotatedSagaRepository.java:174) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.modelling.saga.repository.AnnotatedSagaRepository.lambda$doLoad$2(AnnotatedSagaRepository.java:121) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.MessageProcessingContext.notifyHandlers(MessageProcessingContext.java:71) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.notifyHandlers(DefaultUnitOfWork.java:106) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.changePhase(AbstractUnitOfWork.java:222) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.commitAsRoot(AbstractUnitOfWork.java:83) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.commit(AbstractUnitOfWork.java:71) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.executeWithResult(DefaultUnitOfWork.java:92) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.UnitOfWork.executeWithResult(UnitOfWork.java:328) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.deadline.quartz.DeadlineJob.execute(DeadlineJob.java:134) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.2.jar!/:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) ~[quartz-2.3.2.jar!/:na]
2020-05-28 03:26:13.001 INFO 1 --- [eduler_Worker-1] org.quartz.core.JobRunShell : Job InitializeAuctionEvent.deadline-7e5d9eec-2c7d-4312-9dde-acb9a56abc6b threw a JobExecutionException:
org.quartz.JobExecutionException: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.axonframework.deadline.quartz.DeadlineJob.execute(DeadlineJob.java:143) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.2.jar!/:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) ~[quartz-2.3.2.jar!/:na]
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413) ~[hibernate-core-5.4.15.Final.jar!/:5.4.15.Final]
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1608) ~[hibernate-core-5.4.15.Final.jar!/:5.4.15.Final]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:409) ~[spring-orm-5.2.6.RELEASE.jar!/:5.2.6.RELEASE]
at com.sun.proxy.$Proxy175.executeUpdate(Unknown Source) ~[na:na]
at org.axonframework.modelling.saga.repository.jpa.JpaSagaStore.updateSaga(JpaSagaStore.java:272) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.modelling.saga.repository.AnnotatedSagaRepository.updateSaga(AnnotatedSagaRepository.java:208) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.modelling.saga.repository.AnnotatedSagaRepository.commit(AnnotatedSagaRepository.java:174) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.modelling.saga.repository.AnnotatedSagaRepository.lambda$doLoad$2(AnnotatedSagaRepository.java:121) ~[axon-modelling-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.MessageProcessingContext.notifyHandlers(MessageProcessingContext.java:71) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.notifyHandlers(DefaultUnitOfWork.java:106) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.changePhase(AbstractUnitOfWork.java:222) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.commitAsRoot(AbstractUnitOfWork.java:83) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.commit(AbstractUnitOfWork.java:71) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.executeWithResult(DefaultUnitOfWork.java:92) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.messaging.unitofwork.UnitOfWork.executeWithResult(UnitOfWork.java:328) ~[axon-messaging-4.3.3.jar!/:4.3.3]
at org.axonframework.deadline.quartz.DeadlineJob.execute(DeadlineJob.java:134) ~[axon-messaging-4.3.3.jar!/:4.3.3]
... 2 common frames omitted
Я решил отладить и потратить несколько часов, пытаясь сузить проблему. Я понял, что каким-то образом вне моей кодовой базы (вероятно, Axon magi c) StdScheduler.getContext().get(DeadlineJob.TRANSACTION_MANAGER_KEY)
переопределяется.
Вот 2 снимка экрана, которые подчеркивают проблему:
Как видите, номер экземпляра StdScheduler
13137 содержит SpringTransactionManager
во время инициализации ().
Когда я добавляю точку останова прямо в мою строку планирования, вот скриншот:
Экземпляр StdScheduler
по-прежнему 13137, а QuartzDeadlineManager.transactionManager
по-прежнему содержит экземпляр SpringTransactionManager
. Но теперь StdScheduler.getContext().get(DeadlineJob.TRANSACTION_MANAGER_KEY)
содержит экземпляр NoTransactionManager
, что затем приводит к прерыванию моего выполнения из-за TransactionRequiredException
.
Кто-нибудь испытывал этот сценарий? Как это было смягчено? Прямо сейчас я просматриваю весь код Axon, пытаясь понять, где происходит замена экземпляра.
Спасибо,