Tuesday, August 3, 2010

Event-state modeling in Cordys

 

Case

Recently we have been working on a solution that can be considered as a message broker / hub:

It’s functionality is mainly to receive, validate and route messages between parties in a specific business segment over different channels.

 

All messages have a specific type, syntax and semantics. Messages may be interrelated; e.g. one message may be a response to another message. A business wide protocol-standard describes the complete interrelation between message types, and specifies the possible sequence of messages in a flow: A so called "conversation". In a conversation any message of a specific type can be only followed by a message of one or more other specific types.
In case we want to monitor conversations we need to model the messaging protocol. This protocol can be considered as an event-state diagram: The last received (and expected!) message in the message sequence reflects the state, and the reception of a new message reflects an event.
 
Multiple concurrent conversations may be active at a time. This requires a correlation id to link the reception of a new message (see  the previous blog “Events in Cordys”) to an active conversation (or to start a new one, if there is no flow active for that particular correlation id).

 

Implementation

What does it take to implement such an event-state diagram in Cordys BOP-4?

 

The core of the solution consists of three processes, a decision table and a database-table (with access web services):
  • Monitor-process: A process that describes the state model
  • HandleMessage-process: A process that is started on new receives new messages and that triggers events.
  • WaitForEvent-process: A process that actually waits for an event to be triggered by HandleMessage, where the message is passed
  • StateTransitions-decision table: A decision table containing all valid state transions that can be triggered by a message. 
  • InstanceCorrelation- database table: A database table for storage of the instance id and correlation id

 

Monitor-process

Monitor is the main process. It describes the overal state model. At runtimes each instance reflects a conversation and it effectively keeps the current state of the “conversation”. A Correlation Id is required to correlate the messages to this conversation. The Monitor process simply consists of a number of states that are interrelated: From a particular state an occuring event may cause a transition to one of one or more possible new states. A state is in fact nothing more than a sub-process call to WaitForEvent. WaitForEvent waits for an event and after a correct (expected) message is received it returns the resulting (new) state to the monitoring process. Only in case a state may have more than 1 possible resulting states the monitoring process should use a decision to effectuate the correct transition. All other logic is handles in the WaitForEvent (by invoking the StateTransitions-decision table)
 
Because the Monitor-process is started with the first message of a new conversation it has an input message, having the same format as the messages received by WaitForEvent.
 
     Example of a monitor process

 

WaitForEvent-process

Monitor specifies two main parameters to the WaitForEvent-sub process: The current state of Monitor and the Correlation Id that belongs to the conversation.

The first step in the WaitForEvent is to store its Instance Id in a “InstanceCorrelation” table, together with the Correlation Id before invoking the “Receive Message” step. (See also my previous blog “Events in Cordys”).

Once an event has been triggeredby the HandleMessage-process the WaitForEvent event checks whether it is an event that it expected, depending on the current state. The logic for this check is implemented in the decision table "StateTransitions", that I will explain below.

 

If a message is received that is not an expected successor of the current state, an exception occurs that ought to be handled. (In our case we simply log an “Unexpected Message” error). After this the process waits for a next event to be triggered.

If the message that is received is expected however, the decision table returns the “new state”, which is returned to the monitoring process. Before returning to the monitor however first the InstanceCorrelation table is cleaned up by removing the record that was inserted at the beginning of the process.

 
    "WaitForEvent"-process  
 

HandleMessage-process

HandleMessage is triggered at reception of a new message. It first uses the correlation id in the message to look up a corresponding Instance Id of a waiting process in the InstanceCorrelation table. If no such record is found, we use the decision table to check if the event is an start-event for a new conversation. If so, a new process instance of Monitor is started -via the invokation of a generated Web Service on Monitor-  and passing the message.

In case the Instance Id is found, a notification to WaitForEvent is sent using ExecuteProcess, passing Instance Id and the message (as explained in my previous blog “Events in Cordys”).
 
    "HandleMessage"-process
 
StateTransitions-decision table
The StateTransitions decision table contains all valid "current"state - message combinations, and the resulting new state. (Similar logic may also be implemented e.g. in a matrix, implemented in a database table, see also my blog "logic in Cordys").
 
Note that actually all logic on state transitions is effectively implemented in this decision table, and not in the Monitor process: The Monitor process is only intended to keep the current state of a conversation: Not to execute any transition logic, apart from navigating to the correct new state based on the out-come of the StateTransitions decision table!
 
    "StateTransitions"-decission table
 
Later I will zoom in on the reporting over the monitoring process.
 
 

Regards,

 
Harald van der Weel,

No comments:

Post a Comment