At DecisionCAMP-2020 we had a lot of discussions about the orchestration of the decision services and how to invoke different decision services when states of the business objects change over time. One of the most popular orchestration technique is a Pub/Sub architecture with State machines. The Challenge “Dynamic Loan Approval” is an example of perpetually running decision-making applications which should be able to learn from already executed transactions and evaluate new facts as they become available. This post describes how we implemented this application utilizing OpenRules-based GUI connected to AWS Lambda, EventBridge, SNS, and SQS.
PROBLEM. This challenge deals with the following loan approval scenario as new facts become known as the bank analyzes different facts related to the loan application:
STATE MACHINE. Our implementation follows an event-driven loan approval process demonstrated in this video. Independently of which tools we will use for a pub/sub implementation, to control different states of a loan application we can use a Finite State Machine (FSM), a powerful while intuitive mechanism for state management. FSM can be considered as a special case of a typical DMN-like decision table. For example, here is an OpenRules-based implementation the LoanStateMachine in an Excel table that controls the life-cycle of the loan application:
The first two conditional columns describe different combinations of Loan State(s) and Incoming Event(s), and the action-columns describe what should be done for each combination. Let’s go through this state machine row-by-row.
Rule 1. If the Loan State is New and we received the event New Loan Request, first we should analyze the loan to determine its new status (Approved/Declined) by executing the decision service that Determines the goal “Loan Status” – as you can see actually all rules will execute this service (so we merged all rows in the column “ActionGoal”). Then we will transform the loan into the state “Waiting for Related Facts”, set Waiting Period to 3 days, and will produce a new Outgoing Event “Investigate Related Facts”.
Rule 2. If the Loan State is Waiting for Related Facts and we received the event Loan Request Modified, we again should call the same decision service, leave the loan in the state “Waiting for Related Facts”, set Waiting Period to 7 days, and again produce a new Outgoing Event “Investigate Related Facts”.
Rule 3. If the Loan State is Waiting for Related Facts and we received the event New Related Fact, we again should call the same decision service that is supposed to take into consideration the new fact while evaluating the Loan Status, leave the loan in the state “Waiting for Related Facts”, set Waiting Period to 7 days, and again produce a new Outgoing Event “Investigate Related Facts”.
Rule 4. If the Loan State is Waiting for Related Facts and we received the event Related Fact Modified, we again should call the same decision service that is supposed to take into consideration the modified fact while evaluating the Loan Status, leave the loan in the state “Waiting for Related Facts”, set Waiting Period to 5 days, and again produce a new Outgoing Event “Investigate Related Facts”.
Rule 5. This rule will handle situations when the Loan State is Waiting for Related Facts and the Waiting Period Expired, the fact that probably was automatically generated by an embedded Time Manager. In this case, we again should re-run the same decision service, then transform the loan in the state “Completed“, set Waiting Period to 0 days, and again produce a new Outgoing Event “Loan Analysis Completed”.
Rule 6. This rule will be triggered by the event Finalize that probably will be created by a bank manager after receiving the message from the Rule 5 “Loan Analysis Completed”. In this case, we again should re-run the same decision service to Determine the final Loan Status, transform the loan in the state “Finalized“, set Waiting Period to 0 days, and produce a new Outgoing Event “Loan Analysis Finalized”. After this event probably the application will send an email to a borrower with Loan Status (Approved/Declined) and possible explanations produced by our decision service. The finalized loan probably will be archived in the state “Finalized”.
Rule 7 is needed to handle the situations when a borrower decides to change the loan request (the event “Loan Request Modified”) after it was finalized, e.g. loan amount or loan term were modified. Then the same state machine will continue to manage the loan approval process using the same rules.
With this state machine it’s very simple for a business analyst to modify the number of days between different events or add new events and states. In general state machines similar to the described one are oriented to business people allowing them to describe how to handle different business situations within their complex business processes over time. It is possible to create a functionally similar state machine using for example AWS Steps functions, but it would be difficult for a business person to do it using quite complex JSON representations.
DECISION SERVICE. We decided to implement the decision service as a simple OpenRules project and deploy it as AWS Lambda. Our rules repository contains different OpenRules tables placed in Excel files. We placed the above state machine in the file “StateMachine.xls”. In the file “Rules.xls” we placed the following decision tables that execute loan evaluation logic taking into consideration all already known facts about the loan. The top level decision table compares Global Equaity and Global Debt and sets the correspondent Loan Status and Evaluation Result:
This table calculates different totals:
We assumed that all known facts are placed in the array “Known Securities” where each security in this array has Security Equity and Security Debt. So, we need to iterate through this array
and accumulate Total Equity for All Securities and Total Debt for All Securities:
This is the entire business logic of our decision model. To complete the model we added the Glossary:
To deploy our decision model as AWS Lambda function we define the following “project.properties”:
As usual with OpenRules, it was enough to double-click on standard bat-file “deployLambda.bat” to get our AWS Lambda function “loan-state-machine” up and running.
GUI. To create a graphical interface for our Dynamic Loan Approval application we used OpenRules Dialog. Here is how our GUI looks like at the beginning when no new facts are known:
This GUI allows to enter Loan Request and Borrower Information in the top part of the screen. The next table allows to add/delete different Related Facts as they become known – on the above screen no additional fact are known yet. But we can add the new fact about Joe and Dawn Johnson guarantee and then click on the button “New Related Fact” to invoke our decision service.
The proper request has been sent to the AWS in ASYNC mode, and within a second the updated problem was received and the screen had been changed as follows:
As you can see, the message in the left bottom corner states “Loan Application has been reevaluated” and the Loan Application Status in the box “Results” has been changed from “DECLINED” to “APPROVED” . If you look at the box “Explanation” you will see that the Accumulated Remaining Equity has been also changed from -24,800.00 to 125,200.00. And our GUI is back waiting for new facts for 7 days. We may continue adding related facts as described in the Challenge’s scenario. Below are the proper screens.
After adding Joe Johnson & Bill Smith business loan:
After adding Bill and Susan Smith housing loan:
After adding Tommy Smith educational loan:
This GUI was implemented using OpenRules Dialog where all views are described in simple Excel tables – see all details in this file “LoanStateMachineDialog.xls“.
This dialog uses Java classes that were automatically generated when we build our decision model “LoanStateMachine”.
EVENT MANAGEMENT. All event-buttons in our GUI produce the event of the type “Event”, and when such event occurs our GUI invokes a remote AWS Lambda function using a special class Client.
Initially we used a simple synchronous invocation of the AWS Lambda using a simple Client that utilizes the standard DecisionServiceClient:
Then we wanted to implement a real PUB/SUB mechanism that uses asynchronous invocation of the same AWS Lambda function. We decided to write another client that upon an Event will publish a new topic with the current state of our problem to AWS and will start checking every second if a modified problem has been returned from AWS. To arrange this pub/sub process we used the newest AWS EventBridge in combination with AWS SNS, AWS SQS, and our already deployed AWS Lambda function. This process required quite a few configuration steps at AWS plus creating a special client that knows how to “talk” to AWS:
The entire working applications will be included in the upcoming OpenRules release:
- LoanStateMachine – AWS Lambda in the “openrules.samles”
- LoanStateMachineWithoutEvents – a dialog with sync invocation of the AWS lambda in “openrules.dialog”
- LoanStateMachineWithEventBus – a dialog with async invocation of the AWS lambda in “openrules.dialog”.