关于以下代码;我正在运行 Saga 模式来为列表中的每笔付款执行分布式事务;因为 Rebus 的执行是异步的,所以即使所有 saga 实例都没有完成,我也会直接收到结果。我的问题是;如何让代码等待所有 saga 实例完成然后返回结果?
public class CreatePrelimnaryMoneyTransfersCommandHandler : IRequestHandler<CreatePrelimnaryMoneyTransfersCommand, Result<bool>>
{
private readonly IBus _bus;
private readonly IPaymentRepository _paymentRepository;
public CreatePrelimnaryMoneyTransfersCommandHandler(IBus bus, IPaymentRepository paymentRepository)
{
_bus = bus;
_paymentRepository = paymentRepository;
}
public async Task<Result<bool>> Handle(CreatePrelimnaryMoneyTransfersCommand request, CancellationToken cancellationToken)
{
try
{
var payments = await _paymentRepository.GetPaymentsByQueryParameters(new PaymentQueryParameters { ShowFailedOrChargedBackWithNoPayoutId = true });
foreach (var payment in payments)
{
await _bus.Send(new ExecuteCreatePrelimnaryMoneyTransfersSaga(payment.PaymentId));
}
// this code should be waited until all payments are handled
return new Result<bool>(true, string.Empty);
}
catch (Exception ex)
{
// Handle or log the exception as needed
return new Result<bool>(false, ex.Message);
}
}
}
使用Task.WhenAll遵循此解决方案无助于解决问题;我做到了,但最终我达到了同样的目的。
public async Task<Result<bool>> Handle(CreatePrelimnaryMoneyTransfersCommand request, CancellationToken cancellationToken)
{
var payments = await _paymentRepository.GetPaymentsByQueryParameters(new PaymentQueryParameters { ShowPrelimnaryDeservedPayments = true, LoanId = request.LoanId });
await Task.WhenAll(payments.Select(p => _bus.Send(new ExecuteCreatePrelimnaryMoneyTransfersSaga(p.PaymentId))));
_logger.LogInformation($"I hope I see this log message after all sagas are completed");
return new Result<bool>(true, "Failed payments saved");
}
如果我理解正确的话,您的
ExecuteCreatePrelimnaryMoneyTransfersSaga
命令会启动一个传奇,然后执行一笔付款所涉及的步骤,对吗?
协调这一点的一种方法是使发起付款的逻辑并将其结果关联起来也成为一个传奇 - 这样您就可以在收集到所有付款结果后“做事”。
这当然会导致您的
CreatePrelimnaryMoneyTransfersCommandHandler
请求处理程序无法立即将结果返回给调用者,因为所有逻辑都将在后台异步执行。这通常需要通过提出包含后台处理异步性质的设计来解决。通过拥有正确反映正在发生的事情并等待结论的 UI,可能伴有某种通知机制,让用户知道处理已完成。
我希望这对你来说听起来很明智 🙂