我们有Axon应用程序可以存储新订单。对于每个订单状态更改(OrderStateChangedEvent),它计划几个任务。任务由另一个Saga触发并执行(TaskSaga-超出问题范围)
当我删除投影数据库,但是离开事件存储,然后再次运行应用程序时,将重播事件(正确的事件),但是任务是重复的。
我认为这是因为OrderStateChangedEvent
每次都会触发一组新的ScheduleTaskCommand
。
由于我是Axon的新手,所以无法弄清楚如何避免这种重复。
在AxonServer上运行的事件存储
Spring启动应用程序会自动配置轴突内容
投影数据库包含投影表和轴突表: token_entry saga_entry association_value_entry
我想重播所有事件,因为通过重新创建数据库,Axon表消失了(因此没有关于上一次应用事件的记录)
我想念什么吗?
谢谢!
轴突配置:
@Configuration
public class AxonConfig {
@Bean
public EventSourcingRepository<ApplicationAggregate> applicationEventSourcingRepository(EventStore eventStore) {
return EventSourcingRepository.builder(ApplicationAggregate.class)
.eventStore(eventStore)
.build();
}
@Bean
public SagaStore sagaStore(EntityManager entityManager) {
return JpaSagaStore.builder().entityManagerProvider(new SimpleEntityManagerProvider(entityManager)).build();
}
}
@CommandHandler
public OrderAggregate(CreateOrderCommand cmd) {
apply(OrderCreatedEvent.fromCommand(cmd))
.andThenApply(() -> OrderStateChangedEvent.builder()
.applicationId(cmd.getOrderId())
.newState(OrderState.NEW)
.build());
}
@EventSourcingHandler
protected void on(OrderCreatedEvent event) {
id = event.getOrderId();
// ... additional properties set
}
@EventSourcingHandler
protected void on(OrderStateChangedEvent cmd) {
this.state = cmd.getNewState();
}
private Map<String, TaskStatus> tasks = new HashMap<>();
private OrderState orderState;
@StartSaga
@SagaEventHandler(associationProperty = "orderId")
public void on(OrderStateChangedEvent event) {
orderState = event.getNewState();
List<OrderStateAwareTaskDefinition> tasksByState = taskService.getTasksByState(orderState);
if (tasksByState.isEmpty()) {
finishSaga(event.getOrderId());
}
tasksByState.stream()
.map(task -> ScheduleTaskCommand.builder()
.orderId(event.getOrderId())
.taskId(IdentifierFactory.getInstance().generateIdentifier())
.targetState(orderState)
.taskName(task.getTaskName())
.build())
.peek(command -> tasks.put(command.getTaskId(), SCHEDULED))
.forEach(command -> commandGateway.send(command));
}
答案 0 :(得分:1)
Steven的解决方案就像一个魅力,但仅在Sagas中起作用。对于那些想要达到相同效果但在经典@EventHandler
中(跳过重播执行)的人,有一种方法。首先,您必须找出跟踪事件处理器的命名方式-我在AxonDashboard中找到了它(正在运行AxonServer的8024端口)-通常它是带有@EventHandler
批注的组件的位置(精确的包名称)。然后按照史蒂文在回答中指出的那样添加配置。
@Autowired
public void customConfig(EventProcessingConfigurer configurer) {
// This prevents from replaying some events in @EventHandler
var trackingProcessorConfig = TrackingEventProcessorConfiguration
.forSingleThreadedProcessing()
.andInitialTrackingToken(StreamableMessageSource::createHeadToken);
configurer.registerTrackingEventProcessor("com.domain.notreplayable",
org.axonframework.config.Configuration::eventStore,
c -> trackingProcessorConfig);
}
答案 1 :(得分:0)
在这种情况下,我想可以为您提供帮助。
因此,发生这种情况是因为将所有事件提供给Saga实例的TrackingToken
使用的TrackingEventProcessor
已初始化为事件流的开头。因此,TrackingEventProcessor
将从时间开始开始,从而第二次分发所有命令。
您可以采取一些措施来解决此问题。
initialTrackingToken
的{{1}}配置为从事件流的开头而不是结尾开始。选项1可以解决问题,但是从操作角度来说需要一些委派。选项2交给开发人员,可能比其他解决方案安全一些。
要调整令牌从头开始,可以用TrackingEventProcessor
实例化TrackingEventProcessor
:
TrackingEventProcessorConfiguration
因此,您将为Saga创建所需的配置并调用 EventProcessingConfigurer configurer;
TrackingEventProcessorConfiguration trackingProcessorConfig =
TrackingEventProcessorConfiguration.forSingleThreadedProcessing()
.andInitialTrackingToken(StreamableMessageSource::createHeadToken);
configurer.registerTrackingEventProcessor("{class-name-of-saga}Processor",
Configuration::eventStore,
c -> trackingProcessorConfig);
函数,并确保创建不存在令牌的头部令牌。
我希望这可以帮助您解决Tomáš!