Axon Framework: Change processing order between @EventHandler and @EventSourcingHandler

梦想的初衷 提交于 2019-12-11 18:04:01

问题


My question is how I can change the processing order between an @EventHandler and an @EventSourcingHandler, for the same given Event. I have the @EventSourcinHandler method in an Aggregate class and an @EventHandler in an external class. If i fire an command which results in said event event, my code will run like this:

  1. @EventSourcingHandler
  2. @EventHandler

I want to change this order to this:

  1. @EventHandler
  2. @EventSourcingHandler

I tried the @Order and @ProcessingGroup annotations, but none of these worked for me in regards to adjusting the order.

Here is my Aggregate implementation:

@Aggregate
@Getter
@Setter
@NoArgsConstructor
@Order(2)
@ProcessingGroup("template")
@Component
public class TemplateAggregate {

  private static final transient Logger logger = LoggerFactory.getLogger(TemplateAggregate.class);
  @AggregateIdentifier
  private String templateId;

  private LocalDate createdAt;

  private String createdBy;

  private String description;

  private LocalDate modifiedAt;

  private String modifiedBy;

  private String name;

  private LocalDate validFrom;

  private LocalDate validTo;

  private File file;

  private String fileName;

  private long fileSize;

  private LocalDate fileDate;

  private String fileUploader;

  @CommandHandler
  public TemplateAggregate(CreateTemplateCommand cmd) {
    AggregateLifecycle.apply(new TemplateCreatedEvent(cmd));
  }

  @CommandHandler
  public void handle(ModifyTemplateCommand cmd) {
    AggregateLifecycle.apply(new TemplateModifiedEvent(cmd));
  }

  @EventSourcingHandler
  public void on(TemplateCreatedEvent event) {
    this.templateId = event.getTemplateId();
    this.createdAt = event.getCreatedAt();
    this.createdBy = event.getCreatedBy();
    this.description = event.getDescription();
    this.name = event.getName();
    this.validFrom = event.getValidFrom();
    this.validTo = event.getValidTo();
    this.file = event.getFile();
    this.fileName = event.getFileName();
    this.fileSize = event.getFileSize();
    this.fileDate = event.getFileDate();
    this.fileUploader = event.getFileUploader();
    logger.info("TemplateAggregate - TemplateCreatedEvent");
  }

  @EventSourcingHandler
  public void on(TemplateModifiedEvent event) {
    this.templateId = event.getTemplateId();
    this.createdAt = event.getCreatedAt();
    this.createdBy = event.getCreatedBy();
    this.description = event.getDescription();
    this.name = event.getName();
    this.validFrom = event.getValidFrom();
    this.validTo = event.getValidTo();
    this.file = event.getFile();
    this.fileName = event.getFileName();
    this.fileSize = event.getFileSize();
    this.fileDate = event.getFileDate();
    this.fileUploader = event.getFileUploader();
    this.modifiedAt = event.getModifiedAt();
    this.modifiedBy = event.getModifiedBy();
    logger.info("TemplateAggregate - TemplateModifiedEvent");
  }

}

My External EventHandler class:

@Service
@Order(1)
@ProcessingGroup("template")
@Component
public class TemplateCreatedEventHandler {

  private static final transient Logger logger =
      LoggerFactory.getLogger(TemplateCreatedEventHandler.class);

  @Autowired
  private TemplateRepository templateRepository;

  @Transactional
  @EventHandler
  public void on(TemplateCreatedEvent event) {
    templateRepository.save(new TemplateQueryEntity(event));
    logger.info("EventHandler - TemplateCreatedEvent");
  }

}

I want to do this, because I want to first persist everything in my database, so during this if i get an exception, Axon could not persist in the domain_event_entry table.


回答1:


The @EventSourcingHandler is used for Event Sourcing purposes. It updates the state of your aggregate at two distinct moments: when the event is first applied, in which case it is invoked immediately as part of the apply() method, and secondly when the aggregate state is reconstructed based on its events.

That means the @EventSourcingHandler within an Aggregate will always be invoked before any external event handlers are able to receive the event. This is not something you can change, and quite frankly, I'm sure that's also not what you want.

You mention that you want to be sure that you "want to first persist everything in my database". If you want to work in an event-driven way, this is the first principle to "let go". The primary truth is your events. You'd want to persist these first. Then, as a result of these events, you update the other tables, which feed views, generate other side-effects, etc.

If for whatever reason, you do want to ensure transactional update of your View models and your events, you can assign the Processing Group that contains your external event handler to a Subscribing Processor. This gives you the ability to invoke the Event Handler in the same transaction that also handles the Command (and publishes the events).

Also, I noticed that your aggregate contains a lot of fields. Generally, an Aggregate only needs to contains the fields that are actually used to make decisions on incoming commands. Getters (and Setters, for that matter) on Aggregate Roots in Command Models are generally a design-smell, as they shouldn't need to focus on exposing information at all. The @Order, @ProcessingGroup and @Component annotations on your aggregate have no purpose, and can be removed.



来源:https://stackoverflow.com/questions/57850894/axon-framework-change-processing-order-between-eventhandler-and-eventsourcing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!