
有时,在处理业务操作时,您需要以“发后不理”模式与外部组件进行通信。例如,该组件可以是:
这种与外部组件集成的示例:
随之而来的问题是,从技术角度来看,我们能否保证业务操作的原子性?很遗憾,并非总是如此,即使我们能够做到(使用2PC 协议),从延迟、吞吐量、可扩展性和可用性的角度来看,这也会限制我们的系统。有关这些限制的详细信息,我建议您阅读题为《是时候从两阶段提交迈进了》的文章。
// RegisterCustomerCommandHandler without outbox
public class RegisterCustomerCommandHandler : IRequestHandler<RegisterCustomerCommand, CustomerDto>
{
private readonly ICustomerRepository _customerRepository;
private readonly ICustomerUniquenessChecker _customerUniquenessChecker;
private readonly IEventBus _eventBus;
public RegisterCustomerCommandHandler(
ICustomerRepository customerRepository,
ICustomerUniquenessChecker customerUniquenessChecker,
IEventBus eventBus)
{
this._customerRepository = customerRepository;
_customerUniquenessChecker = customerUniquenessChecker;
_eventBus = eventBus;
}
public async Task<CustomerDto> Handle(RegisterCustomerCommand request, CancellationToken cancellationToken)
{
var customer = new Customer(request.Email, request.Name, this._customerUniquenessChecker);
await this._customerRepository.AddAsync(customer);
await this._customerRepository.UnitOfWork.CommitAsync(cancellationToken); // commit transaction
// End of transaction--------------------------------------------------------
this._eventBus.Send(new CustomerRegisteredIntegrationEvent(customer.Id)); // send an event
return new CustomerDto { Id = customer.Id };
}
}第 24 行执行完成后,事务提交。在第 28 行,我们想将事件发送到事件总线,但不幸的是,可能会发生两件糟糕的事情:

如果我们不能提供原子性,或者由于上述原因我们不想这样做,那么我们可以做些什么来提高系统的可靠性呢?我们应该实现发件箱模式。
发件箱模式基于保证交付模式,如下所示:

当您将数据保存为一个事务的一部分时,您也会将稍后要处理的邮件保存为同一事务的一部分。待处理的邮件列表称为“发件箱”,就像在电子邮件客户端中一样。
难题的第二个要素是一个单独的进程,它会定期检查发件箱的内容并处理邮件。处理完每条邮件后,应将其标记为已处理,以避免重复发送。但是,由于与发件箱的通信错误,我们可能无法将邮件标记为已处理:

在这种情况下,当与发件箱的连接恢复后,同一条消息将再次发送。这对我们意味着什么?发件箱模式提供至少一次的传递。我们可以确保消息只会发送一次,但也可以发送多次!这就是为什么这种方法的另一个名称是“一次或多次传递”。我们应该记住这一点,并尝试将消息的接收者设计为幂等的,这意味着:
在消息传递中,此概念指的是无论接收一次还是多次,消息的效果都相同。这意味着即使接收方收到同一条消息的副本,也可以安全地重新发送该消息,而不会造成任何问题。
参考:
https://microservices.io/patterns/data/transactional-outbox.html
https://www.kamilgrzybek.com/blog/posts/the-outbox-pattern
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。