You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axon Saga中CanceledPreemptProductEvent处理器内OrderInfoDto为空问题排查

Axon Saga 状态丢失导致空指针异常问题

在Spring Boot结合Axon实现微服务架构时,遇到Saga状态丢失问题:StartedOrderSagaEvent处理器中设置的OrderInfoDto对象,在CanceledPreemptProductEvent处理器执行时变为null,触发空指针异常。已配置JPA作为Saga存储,但OrderInfoDto未被持久化到saga_entry表的serialized_saga列。

相关代码

OrderSaga.java

@Saga
@ProcessingGroup("orderSagaProcessor")
@Slf4j
public class OrderSaga {
    @Transient
    private transient CommandGateway commandGateway;

    private OrderInfoDto orderInfoDto;

    @Autowired
    public void setCommandGateway(CommandGateway commandGateway) {
        this.commandGateway = commandGateway;
    }

    @StartSaga
    @SagaEventHandler(associationProperty = "orderUuid")
    public void handle(StartedOrderSagaEvent event) {
        log.info("[OrderSaga] Order Saga started for orderUuid: {}", event.getOrderUuid());
        this.orderInfoDto = new OrderInfoDto(event.getOrderUuid(), event.getName(), event.getPhoneNumber(), 0, OrderState.PROCESS, null, null);
    }

    @SagaEventHandler(associationProperty = "orderUuid")
    public void handle(CanceledPreemptProductEvent event) {
        log.error("[OrderSaga] Failed preempt product for orderUuid: {}", event.getOrderUuid());
        
        // NullPointerException occurs here because orderInfoDto is null
        this.orderInfoDto.getProductItems().forEach(productItem -> {
            commandGateway.send(new CancelPreemptionCommand(productItem.getProductUuid(), productItem.getCount()));
        });
    }
}

OrderInfoDto.java

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class OrderInfoDto implements Serializable {
    private String orderUuid;
    private String name;
    private String phoneNumber;
    private int total;
    private OrderState state;
    private List<ProductItem> productItems;
    private String paymentUuid;

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class ProductItem implements Serializable {
        private String productUuid;
        private int price;
        private int count;
    }
}

application.yml

axon:
  axonserver:
    servers: localhost:8124
  eventhandling:
    processors:
      orderSagaProcessor:
        mode: tracking
        source: eventStore
      orderAggregateProcessor: # Processor 이름
        mode: tracking
        source: eventStore
  saga:
    store: jpa
  serializer:
    general: jackson
    events: jackson
    messages: jackson

疑问

  1. 在Saga内部以变量形式存储OrderInfoDto是否存在错误?
  2. 若该方式不正确,Axon Saga中持久化有状态数据的最佳实践是什么?
  3. 该问题是否与序列化配置(axon.serializer.general: jackson)相关?

问题解答

1. Saga内部存储OrderInfoDto的方式是否错误?

本身没有语法错误,但存在两个关键问题:

  • Axon的Saga仅会在事件处理方法执行完毕后、或显式调用SagaLifecycle#end()时持久化状态。如果StartedOrderSagaEvent处理完成后,Saga未触发持久化逻辑(比如未关联后续事件导致Saga被判定为结束),后续事件触发时就加载不到之前设置的orderInfoDto。
  • 需确认OrderState枚举是否实现了Serializable接口:如果枚举未序列化,会导致整个OrderInfoDto序列化失败,进而无法持久化。

2. Axon Saga持久化有状态数据的最佳实践

  • 确保所有状态字段可序列化:所有需要持久化的Saga成员变量(包括嵌套对象、枚举)必须实现Serializable接口。
  • 依赖Axon自动持久化机制:每个@SagaEventHandler方法执行完成后,Axon会自动持久化Saga状态;处理事件时,需通过SagaLifecycle.associateWith(...)关联后续可能触发的事件标识(你的场景中已通过associationProperty关联orderUuid,这一步没问题)。
  • 标记非持久化字段:不需要持久化的字段(比如CommandGateway)必须用transient修饰,避免序列化失败。
  • 简化Saga状态:仅存储必要的核心业务数据,不要将大对象或无关数据放入Saga,减少序列化开销和存储风险。

3. 是否与Jackson序列化配置相关?

有可能,需检查以下几点:

  • 枚举序列化正确性:如果OrderState枚举有自定义逻辑,需确保Jackson能正确处理(比如添加@JsonFormat或自定义序列化器)。
  • 嵌套对象与集合序列化:确认Jackson能正常序列化List<ProductItem>这类集合类型,内部静态类ProductItem已实现Serializable,这部分基础没问题。
  • 查看序列化日志:开启Axon调试日志,排查是否有序列化异常被隐藏:
    logging:
      level:
        org.axonframework: DEBUG
    
    若序列化失败,日志中会有明确报错,这会直接导致Saga状态无法持久化,后续加载时orderInfoDto即为null。

内容的提问来源于stack exchange,提问作者드가자

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 05:53:14