Java 轴突-始终重新投影所有事件
是否可以使用SubscriptingEventProcessors使用Java 轴突-始终重新投影所有事件,java,axon,Java,Axon,是否可以使用SubscriptingEventProcessors使用,并且在投影事件时,始终从一开始就重新投影所有事件。意思是-我从不将投影保存到DB,但只要聚合中发出新事件,就重新投影所有事件?当然这是可能的! 但是,使用订阅事件处理器无法实现这一点。 您应该利用跟踪事件处理器,但在其后面有一个InMemoryTokenStore。这样,应用程序就永远不能从它停止的地方开始,因为它停止的地方的知识,TrackingToken,并不存在 因此,每次启动时都会重新创建投影 您可以采取的另一种方法
,并且在投影事件时,始终从一开始就重新投影所有事件。意思是-我从不将投影保存到DB,但只要聚合中发出新事件,就重新投影所有事件?当然这是可能的!
但是,使用订阅事件处理器无法实现这一点。
您应该利用跟踪事件处理器,但在其后面有一个InMemoryTokenStore
。这样,应用程序就永远不能从它停止的地方开始,因为它停止的地方的知识,TrackingToken
,并不存在
因此,每次启动时都会重新创建投影
您可以采取的另一种方法有点不同。
您仍然可以使用跟踪事件处理器,但需要实际的持久化TokenStore
实现。其次,在应用程序启动时,您可以使用TrackingEventProcessor#resetTokens()
函数发布给定跟踪事件处理器的重播
采用这种方法,您可以在事件处理组件中添加带注释的函数@ResetHandler
,以便在再次处理所有事件之前清除投影表
希望这能给你一些见解博扬 @Steven你觉得这个解决方案怎么样
public class ReplayingSubscribingEventProcessor extends SubscribingEventProcessor {
private final SubscribableMessageSource<? extends EventMessage<?>> messageSource;
protected ReplayingSubscribingEventProcessor(
Builder builder) {
super(builder);
this.messageSource = builder.messageSource;
}
public static Builder builder() {
return new Builder();
}
/**
* Whenever there is a need to process event messages, ignore all of them and since already inside messageSource,
* just take all messages from event source and re-project all from beginning for this aggregate root
* @param eventMessages
*/
@Override
protected void process(List<? extends EventMessage<?>> eventMessages) {
try {
//reprocess all previous events for this aggregate (get id from current event)
GenericDomainEventMessage gdem = (GenericDomainEventMessage) eventMessages.get(0);
List<? extends EventMessage<?>> prevEvs = ((EventStore)messageSource).readEvents(gdem.getAggregateIdentifier()).asStream()
.collect(Collectors.toList());
processInUnitOfWork(prevEvs, new BatchingUnitOfWork<>(prevEvs), Segment.ROOT_SEGMENT);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new EventProcessingException("Exception occurred while processing events", e);
}
}
public static class Builder extends SubscribingEventProcessor.Builder{
private SubscribableMessageSource<? extends EventMessage<?>> messageSource;
@Override
public Builder messageSource(
SubscribableMessageSource<? extends EventMessage<?>> messageSource) {
super.messageSource(messageSource);
this.messageSource = messageSource;
return this;
}
@Override
public ReplayingSubscribingEventProcessor.Builder name(String name) {
super.name(name);
return this;
}
@Override
public ReplayingSubscribingEventProcessor.Builder eventHandlerInvoker(
EventHandlerInvoker eventHandlerInvoker) {
super.eventHandlerInvoker(eventHandlerInvoker);
return this;
}
@Override
public ReplayingSubscribingEventProcessor.Builder processingStrategy(
EventProcessingStrategy processingStrategy) {
super.processingStrategy(processingStrategy);
return this;
}
public ReplayingSubscribingEventProcessor build() {
return new ReplayingSubscribingEventProcessor(this);
}
}
}
公共类ReplayingSubscribingEventProcessor扩展SubscribingEventProcessor{
private final SubscribableMessageSource>messageSource;
受保护的ReplayingSubscribingEventProcessor(
建筑商(建筑商){
超级建筑商;
this.messageSource=builder.messageSource;
}
公共静态生成器(){
返回新的生成器();
}
/**
*每当需要处理事件消息时,忽略所有消息,因为已经在messageSource中,
*只需从事件源获取所有消息,并从此聚合根开始重新投影所有消息
*@param eventMessages
*/
@凌驾
受保护的无效进程(列表>事件消息){
试一试{
//重新处理此聚合的所有以前的事件(从当前事件获取id)
GenericDomainEventMessage gdem=(GenericDomainEventMessage)eventMessages.get(0);
List>prevEvs=((EventStore)messageSource.readEvents(gdem.getAggregateIdentifier()).asStream()
.collect(Collectors.toList());
processInUnitOfWork(prevEvs,新批处理InUnitOfWork(prevEvs),Segment.ROOT\u段);
}捕获(运行时异常e){
投掷e;
}捕获(例外e){
抛出新的EventProcessingException(“处理事件时发生异常”,e);
}
}
公共静态类生成器扩展SubscribingEventProcessor.Builder{
private SubscribableMessageSource>messageSource;
@凌驾
公共生成器消息源(
SubscribableMessageSource>messageSource){
super.messageSource(messageSource);
this.messageSource=messageSource;
归还这个;
}
@凌驾
公共ReplayingSubscribingEventProcessor.Builder名称(字符串名称){
超级名称(名称);
归还这个;
}
@凌驾
公共ReplayingSubscribingEventProcessor.Builder eventHandlerInvoker(
EventHandlerInvoker(EventHandlerInvoker){
super.eventHandlerInvoker(eventHandlerInvoker);
归还这个;
}
@凌驾
公共ReplayingSubscribingEventProcessor.Builder处理策略(
事件处理策略(事件处理策略){
超级加工战略(加工战略);
归还这个;
}
公共ReplayingSubscribingEventProcessor build(){
返回新的ReplayingSubscribingEventProcessor(此);
}
}
}
和配置:
@Autowired
public void configure(EventProcessingConfigurer configurer){
configurer.registerEventProcessor("inMemoryProcessor",
(n, c, ehi) -> replayingSubscribingEventProcessor(n, c, ehi, org.axonframework.config.Configuration::eventBus));
}
public ReplayingSubscribingEventProcessor replayingSubscribingEventProcessor(
String name,
org.axonframework.config.Configuration conf,
EventHandlerInvoker eventHandlerInvoker,
Function<org.axonframework.config.Configuration, SubscribableMessageSource<? extends EventMessage<?>>> messageSource) {
return ReplayingSubscribingEventProcessor.builder()
.name(name)
.eventHandlerInvoker(eventHandlerInvoker)
.messageSource(messageSource.apply(conf))
.processingStrategy(DirectEventProcessingStrategy.INSTANCE)
.build();
}
@Autowired
公共无效配置(事件处理配置器配置器){
configurer.registerEventProcessor(“inMemoryProcessor”,
(n,c,ehi)->replayingSubscribingEventProcessor(n,c,ehi,org.axonframework.config.Configuration::eventBus);
}
公共重播SubscriptingEventProcessor重播SubscriptingEventProcessor(
字符串名,
org.axonframework.config.conf配置文件,
EventHandlerInvoker EventHandlerInvoker,
功能我刚刚使用InMemoryTokenStore
和配置器。registerTokenStore(“inMemoryProcessor”,cfg->InMemoryTokenStore());
和带有@ProcessingGroup(“inMemoryProcessor”)的带注释投影仪进行了设置
。现在我看到的是跟踪事件处理器不断轮询来自DB的事件。是否可以仅在调用@QueryHandler
带注释的方法而不是之前进行投影?基本上,我发送eg id=1的请求,该方法知道,在该时间点,它需要从该aggreg重新投影所有事件ate并返回当前投影(不保存到db)?好的,我刚刚将queryResult.updates().blockFirst()
更改为queryResult.initialResult().block()
并且它似乎返回了正确的投影结果。它似乎返回了我猜是上一个投影的东西?如果我使用“更新”,它只是挂在一个循环队列中来自DomainEventEntry e,其中e.globalIndex>:token
。是的,只有当查询在上传入时,才能创建投影de>@QueryHandler
带注释的函数。不过,这需要一些个人实现。Axon在其内部深处使用注释EventListenerAdapter
包装带@EventHandler
注释的类,以便能够使用事件流调用它。您可以在@QueryHandl中包装投影呃
从事件存储中提取事件流
并自己处理这个过程。我以前做过,但只有你能决定这个家庭作业是否可取。谢谢。你有这样的例子吗?还有-知道为什么在m中不触发updates()