Eventual consistency and delayed projection updates

We have a loan system which deals with customer scoring and approving loan/financing applications (CreditApplicationAggregate). Once customer is approved, LoanAgreementAggregate is created and credit limit balance is assigned to them (CustomerBalanceAggregate) which keeps track of all balance related transactions. When limit is already assigned to customer and they apply for new credit, then available balance check is performed.

We have relied on query based validation against available balance before application gets created and before it gets finally approved/signed and it has worked fine so far. Recently (in 4 years) we had 2 incidents where the projection update was delayed for more than ~1 minute and customer was able to create many withdrawals from their balance because the projection was not updated and available balance was wrong which resulted in customer getting more balance than their max limit allowed. Whole application and approval process is automated, no human is involved except customer itself.

The flow is simple:

  • LoanAgreementSignSaga is started when CreditApplicationAggregate is approved.
  • LoanAgreementSignSaga creates LoanAgreementAggregate
  • Customer signs loan agreement and LoanAgreementSignedEvent finalizes the agreement
  • LoanAgreementSignSaga handles LoanAgreementSignedEvent and executes DecreaseUsedLimitAmountCommand on CustomerBalanceAggregate to reduce its used balance amount.
  • UsedLimitAmountDecreasedEvent is handled in projector to update the view model which is used to through queries to validated used amount/available balance when new application is created

When multiple loan applications are issued in quick succession then the UsedLimitAmountDecreasedEvent may lag behind and not get updated in time.

What is the correct design solution here to prevent this from happening? I cannot rely on projection queries here. Should the solution be to execute some kind of validation command on the CustomerBalanceAggregate which validates the balance on aggregate instead? Or should the flow be another way around where CustomerBalanceAggregate must validate balance on aggregate first before the saga can continue?

Any suggestions are welcome!

In cases like this, you can reserve the amount needed from the Saga with a Command. In that case, it is important that if the loan can’t be approved, the reservation is removed again. This might introduce problems if you want to have multiple loan agreements pending, for which there might not be enough room to reserve enough credit. To prevent this, reserving the credit should be a last step, just before approving the loan. It makes the model a bit more complex, but this way you can ensure consistancy.

Thanks that seems reasonable solution. We already use reservations for funds withdrawal, so likely can make it work for this use case as well. Thanks!

1 Like