我们正在重新设计一些 REST API 端点,以过渡到微服务架构。
在这里,我们正在研究端点/invitations/:id/confirm
。
此端点使用提供的Invitation
创建User
,Account
。
我们有 3 个聚合体Invitation
、User
和Account
个。
我们目前遵循的标称流量为:
- 检查
Invitation
是否存在 - 确保邀请可以确认
- 创建
User
- 创建
Account
- 删除
Invitation
- 退货
UserId
此操作是在进程中完成的,这解释了为什么我们可以立即返回 UserId。我们只需从数据库加载聚合,执行关联的业务逻辑并保留结果。
引入微服务将需要异步处理。换句话说,我们应该向总线发送命令并返回状态代码 202。
在我们的计划中,我们要触发一个名为RequestInvitationConfirmation
的命令。实例化此命令时将进行基本验证。
然后,此命令将通过总线发送给负责以下各项的消费者: - 加载邀请聚合(确保它存在( - 调用请求确认方法(将检查是否可以确认邀请( - 提高InvitationConfirmationRequested
事件
InvitationConfirmationRequested
事件将触发负责编排跨服务通信的 SAGA
OnInvitationConfirmationRequested
- 发送
CreateUser
命令
- 发送
OnUserCreated
- 发送
CreateAccount
命令
- 发送
OnAccountCreated
- 发送
DeleteInvitation
命令
- 发送
OnInvitationDeleted
- 提高
InvitationConfirmed
- 提高
由于它是异步的,我们需要提供一种获取当前操作状态的方法。我看到(https://www.adayinthelifeof.nl/2011/06/02/asynchronous-operations-in-rest/,https://asyncrestapi.docs.apiary.io/#(一种常见的方法 是提供/queue/:id
或/actions/:id
终结点。
这就是我们感到困惑的地方。当 SAGA 的状态可能完全不同时,您如何提供单个端点?
感谢
要使 saga 在单个流范围内处理消息,您必须将所有消息与适当的实例相关联。当 saga 由第一条消息启动时,将根据以下规则生成 saga 标识:
Event(() => ItemAdded, x => x.CorrelateBy(cart => cart.UserName, context => context.Message.UserName)
.SelectId(context => Guid.NewGuid()));
因此,此 id 将用作持久保存到 saga 存储库的 saga 的标识。
class ShoppingCart :
SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public string CurrentState { get; set; }
在这里,CorrelationId
是 saga id,因此是整个过程的相关 id。
如果您有权访问 saga 存储库(并且您确实有权访问(,则很容易公开 HTTP API 端点以检索当前 saga 状态,方法是在用于持久保存 saga 的数据库中查看 saga 状态中的CurrentState
属性的值。