Validation 异步SAGA模式中的验证-CQRS&;DDD 我们考虑下面的流程: API客户端调用[POST]/API/v1/invitation/:InvitationId/confirm 在一个传奇故事中确认邀请 最终引发一个邀请确认的事件以表明成功
我们很难找到一个好地方来验证我们传递给传奇的“事件”。例如,我们希望确保: -指定的Validation 异步SAGA模式中的验证-CQRS&;DDD 我们考虑下面的流程: API客户端调用[POST]/API/v1/invitation/:InvitationId/confirm 在一个传奇故事中确认邀请 最终引发一个邀请确认的事件以表明成功,validation,domain-driven-design,cqrs,saga,Validation,Domain Driven Design,Cqrs,Saga,我们很难找到一个好地方来验证我们传递给传奇的“事件”。例如,我们希望确保: -指定的邀请ID存在 -相应的邀请未过期或尚未处理 我们尝试了两种方法: 发出命令: 启动命令RequestInvitationConfirmation 同步处理此命令,如果该命令无效或引发邀请确认请求事件,则返回错误 流的其余部分是相同的 缺点: -要求我们遵循“请求/响应”模式(在HTTP请求生存期内同步) 提出一项活动: 提出一个事件邀请确认请求 在SAGA中,查询邀请服务并执行验证。如果命令无效,我们将发布
邀请ID
存在
-相应的邀请未过期或尚未处理
我们尝试了两种方法:
- 启动命令
RequestInvitationConfirmation
- 同步处理此命令,如果该命令无效或引发
邀请确认请求事件,则返回错误
- 提出一个事件
邀请确认请求
- 在SAGA中,查询
服务并执行验证。如果命令无效,我们将发布一个事件邀请
(……)InvitationConfirmationFailed
验证是一个非常常见的概念。在分布式完全异步系统中如何处理它?您有一个命令
ConfirmInvitation
包含邀请ID
。您可以通过InvaitionAppService
将其发送到您的邀请
域。您的邀请
域应该如下所示
...
public void ConfirmInvitation()
{
if (this.Status == InvitationStatus.Confirmed)
throw new InvalidInvitationException("Requested invitation has already been confirmed");
//check more business logic here
this.Status = InvitationStatus.Confirmed;
Publish(new InviationConfirmedEvent(...));
}
...
您的InvitationAppService
应该具有以下内容:
...
public void ConfirmInvitation(Guid invitationId)
{
// rehydrate your domain from eventstore
var invitation = repo.GetById<Invitation>(invitationId);
if (invitation == null)
throw new InvalidInvitationException("Invalid Invitation requested");
invitation.ConfirmInvitation(new ConfirmInvitation(...));
}
。。。
公开无效确认(Guid邀请ID)
{
//从eventstore重新水化您的域
var invitation=repo.GetById(invitationId);
如果(邀请==null)
抛出新的InvalidVitationException(“请求的邀请无效”);
邀请.确认书(新确认书(…);
}
您不需要引入新的事件
邀请确认请求
。DDD是一种域/业务验证应该驻留在域内的方法。不要尝试在您的领域中采用其他模式或技术。在saga中验证您的域(用于协调跨服务的分布式事务)可能会造成复杂性和混乱此系统设计中的重要一点是:“谁是此API的客户?”
- 如果此客户端是内部
或服务
,那是一回事(如分布式应用程序、微服务等)应用程序
- 如果API被第三方客户端使用,那是另一回事
服务之间内部使用
,则在系统中发送Id无效的命令是错误的,因此系统开发人员应记录并检查该命令。同样,此类情况也应该通过手动方式解决(通过一些管理后端)。记录这些内容并通知开发人员
如果API是从第三方应用程序使用的,那么API和它使用的系统的其他部分之间的责任如何划分就很重要了。让API负责验证,不要发送id无效的命令。将ID无效的命令视为错误,与第一种情况相同。在这种情况下,如果您使用异步流,您将需要一种与第三方应用程序通信的方式来通知它。你可以用类似的东西
对于验证检查的第二部分和
长话短说
如果你四处搜索,你会看到很多关于错误和验证的讨论,下面是我对此的看法
由于我们对系统的其他部分进行了分离,因此分离我们所存在的错误类型似乎是很自然的。你可以看看这个话题
让我们定义一些错误类型
- 域错误
- 应用程序错误
- 技术错误(数据库连接丢失等)
- 操作的请求者和接收者
- 使用的通信通道
- 通信类型:同步或异步
- 验证具有指定的
的Id
邀请是否存在
- 验证
邀请是否未过期
- 验证邀请是否尚未处理(已接受、已拒绝等)
CommandCreator
在发送命令之前验证具有指定Id
的邀请是否存在
在使用API的情况下,将接受请求的RouteHandler
(应用程序控制器等)必须:
- 请自行执行此验证