Axon如何在saga中捕获异常

huangapple go评论110阅读模式
英文:

Axon how can I catch exception in saga

问题

假设我想创建一个简单的请求-批准系统如果用户向另一个用户发出请求它应该创建该请求因此我有两个聚合**用户请求**请求创建后它将触发**RequestSaga**以发送**RequestUserCmd**

    //聚合类
    @Aggregate
    class RequestAggregate {
      @AggregateIdentifier
      private lateinit var requestId: String
    
      @CommandHandler
      constructor(cmd: CreateRequestCmd){
        apply(RequestCreatedEvt(
            ...一些参数
        ))
      }
    }
    
    @Aggregate
    class UserAggregate {
      @TargetAggregateIdentifier
      private lateinit var userId: String
      private var available = false
    
      // 其他一些命令
      @CommandHandler
      constructor(cmd: RequestUserCmd){
        if(!available) throw IllegalArgumentException("用户不可用。")
        apply(UserRequestedEvt(
            ...一些参数
        ))
      }
    }

    //Saga类
    @Saga
    class RequestSaga {
      @Autowired
      @Transient
      private lateinit var commandGateway: CommandGateway
    
      @StartSaga
      @SagaEventHandler(associationProperty = "requestId")
      fun on(evt: RequestCreatedEvt){
        commandGateway.sendAndWait<String>(RequestUserCmd(
            ...一些参数
        ))
      }
    }

我期望的是如果用户此时不可用它应该引发异常而请求不应该被创建

    @RestController
    class RequestController {
      // 其他代码...
      @PostMapping
      fun request(@RequestBody request: Request){
        // 如果用户不可用,我希望返回 403 错误请求
        commandGateway.send<String>(CreateRequestCmd(
            ...一些参数
        ))
      }
    }

但实际上在用户此时不可用的情况下请求仍然成功被创建我应该如何解决这个问题
英文:

Suppose I want to create a simple request-approve system, If the user requests for something to another user it should create the request so I have two aggregates User, Request. After the request has been created it will trigger RequestSaga to send RequestUserCmd

//Aggregate class
@Aggregate
class RequestAggregate {
@AggregateIdentifier
private lateinit var requestId: String
@CommandHandler
constructor(cmd: CreateRequestCmd){
apply(RequestCreatedEvt(
...some arguments
))
}
}
@Aggregate
class UserAggregate {
@TargetAggregateIdentifier
private lateinit var userId: String
private var available = false
// Some other commands
@CommandHandler
constructor(cmd: RequestUserCmd){
if(!available) throw IllegalArgumentException(&quot;User is not available.&quot;)
apply(UserRequestedEvt(
...some arguments
))
}
}
//Saga class
@Saga
class RequestSaga {
@Autowired
@Transient
private lateinit var commandGateway: CommandGateway
@StartSaga
@SagaEventHandler(associationProperty = &quot;requestId&quot;)
fun on(evt: RequestCreatedEvt){
commandGateway.sendAndWait&lt;String&gt;(RequestUserCmd(
...some arguments
))
}
}

what I expected is, if the user is not available at that time it should raise exception and the request should not been created.

@RestController
class RequestController {
// something...
@PostMapping
fun request(@RequestBody request: Request){
// if the use is not available i want it to return 403 bad request instead
commandGateway.send&lt;String&gt;(CreateRequestCmd(
...some arguments
))
}
}

but in reality, the request has been created successfully even the user is not available at that time how do I manage to solve this case.

答案1

得分: 1

RequestSaga(或任何一种Saga实现)应意识到它发送的操作可能会失败。它是您的“复杂业务交易”的核心,其中也包括错误情况。

因此,您应该意识到从RequestSaga发送的RequestUserCmd可能会失败。由于您正在使用CommandGateway#sendAndWait(Object)方法,这意味着命令处理函数抛出的异常将可以在Saga中捕获。因此,在sendAndWait周围放置一个简单的try-catch块就可以了。

如何应对异常完全取决于您的领域。也许您会重试该操作?或者您可以安排一个截止时间在5分钟后重试该操作?还是5天后?或者您可以发送另一个命令回到请求服务,说明用户不可用?

对于这个问题,没有“一刀切”的解决方案,因为只有您的领域专家才能告诉您如果这样的操作失败,您应该做什么。

无论如何,希望这对您有所帮助,@Patrick。如果我的回答不清楚,请添加一些评论,我会看看如何更新我的答案以满足您的需求。

英文:

The RequestSaga (or any Saga implementation for that matter) should be aware that operations it sends might fail. It is the heart of your "complex business transaction", which also includes faulty scenarios.

Thus, you should be aware that the RequestUserCmd you send from the RequestSaga can fail. As you are using the CommandGateway#sendAndWait(Object) method, that means the exception thrown by the command handling function will be catchable in the Saga. Thus a simple try-catch block around the sendAndWait will do.

How your react on the exception is however entirely up to your domain. Maybe you retry the operation? Or maybe you schedule a deadline to retry the operation in 5 minutes? Of in 5 days? Or maybe you can send another command back to the request service stating the user is unavailable?

There is no "one size fits all" solution to that question, as only your domain expert can tell you what you should be doing if such an operation fails.

Regardless, I hope this helps you out @Patrick. Please add some comments if my response is unclear to you and I'll see how to update my answer to tailor those needs.

huangapple
  • 本文由 发表于 2020年6月29日 15:05:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/62632885.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定