So I've got some complex business logic that is backing an ASP.NET Core API, that is starting to get unwieldly due to the size and I was hoping I could get some advice on better approaches. An example request might have a route of /accounts/{accountId:guid}/approve
, and when that endpoint is called we need to do the following operations:
- Get the account from a Cosmos DB
- Example account entity:
{"id": "<SOME_GUID>", "accountNumber": "C12345", "status": "Pending"}
- Example account entity:
- Perform checks on the account to ensure it is valid to be approved
- Perform checks against other entities in the Cosmos DB
- E.g. No other account is approved with an
accountNumber
matching this account
- E.g. No other account is approved with an
- Update the account in the Cosmos DB
- Send events to the Azure Event Grid informing of approval
- Send email notifications
- Done via Azure Event Grid, but that's more of an implementation detail
- Update the audit records for the account in the Cosmos DB
- I know Cosmos DB has some auditing functionality, but it doesn't suit our purposes and thus we manage a second set of entities for auditing.
Now obviously some of those steps need to be done before others (e.g. you can't run checks on the account before getting it from the Cosmos DB), and we want to exit out early indicating the error if one of the steps fails (e.g. if updating the account in the Cosmos DB fails we don't want to update the audit records).
Currently we have a system I architectured that uses a series of operations to perform the steps sequentially exiting out early if there are any errors. There is good use of generics to allow very common steps such as getting an entity by it's ID to be placed into the sequence of operations without any other implementation. This system works alright, but even with the work I've done implementing even similar endpoints (think /accounts/foo/{accountId:guid}/approve
and /accounts/bar/{account:Id:guid}/approve
isn't as fast as we'd like, and every change to business rules requires changes to code.
I've looked online and struggled to find a system that fits with our requirements. Essentially we need a system for implementing the following requirements for our business logic:
- Run rules sequentially
- A bonus would be the ability to run some rules in parallel where it makes sense
- Run rules for which the state changes throughout the rules
- Exit out of rules early if an error state occurs