Wednesday, September 3, 2008

Asynchronous State Machine Pattern. (The C# Way)

Experienced Software developers/programmers and architects enjoys separation of concern approach when building reusable components using the domain engineering practice.
We all understand that as part of separating application concerns, we need to ensure that our applications are purely decoupled away from dependencies and we need to ensure we properly inject those dependencies without coupling.

As we mature in decoupling our applications and components, we also must understand that, as part of dependency injection, we need to understand the underlying theories behind the publisher and subscriber pattern (Popularly known as fire and forget). Experience have shown that writing application without decoupling in mind is a way of creating problems for the nearer future, this approach is referred to conventional based application engineering. Most developers win and rush to market by launching an application that is very difficult to debug, an application that is overly designed , an application that is very tightly coupled and does not give room to changing and demanding business cases.

We can imagine two processes that handles heavy jobs (like handling about 50,000 calls in a day) coded in a more tightly coupled manner, these processes, by all standards, can handle their concerns differently without one waiting for the other to finish executing. In a service oriented architecture, where business processes are shipped/designed as web services/windows services, we need to carefully understand when to use an asynchronous call and a synchronous call, because of the load involved in processing a request.

Scenario 1
Let us all look at this simple analogy: We have a Business Process Services that handles our business processes like our internal/ and external business concerns. Our business process services comprises of the following functionality :
  1. Register new customer
  2. Register with payment gateway
  3. Send notifications
  4. make periodical payment
  5. Calculate due payment
  6. Daily status monitoring.
Before i go ahead talking more about our area of concern, i would like to introduce a simple architectural diagram of our case study, so that you can catch a glimpse of what big picture i have got in my mind. Here we go, architecture :

The architecture digram above, shows that our business process handles several business functionalities, so it wont be wise to do a synchronous call on our business service's. One of the scenario that we may need to use the separation of concern strategy i have been talking about is when we happen to be in the following scenario :

The daily processor runs.
The status functionality Begins.
The payment is calculated.
Notification is sent. (Based on status).

At the end of each business cycle processing, i mean, our business logic processing, the end task is to send a notification (email). If we have more than 40, 000 status checks, which in turn leads to thousands of business criteria to meet. I mean if we call the method in our service (CheckStatus()) 40, 000 times, a single call will invoke several operations, several operations will launch other legacy stuffs, other legacy stuffs will have their own custom built operations as well, we can see that for a single operations, the load on the Business service is very high, what about for 40, 000 operations. As we must remember, the process calling our business service is also tide with our service until the notifications is sent.

It would be very nice to tell our business process that a customer needs status checks, and thats all, we do not need to wait for our business process to tell us yes or no. All we are satisfied with is that we handled the call to business process. Then asynchronously, our business process will handle all the dirty work without locking its caller. So we now understand where to use asynchronous communication, let us diggit with code :


First of all we need to create the event argument that is raised when a status has been meet. Note* i wont be writing full code here, as readers are assumed to be an experienced developer.



public class StatuChangeEventArgs : EventArgs
{
CustomerState CustomerState{get; set;}

public StatuChangeEventArgs(Customer customer){ //Initialize here. }
}

public enum CustomerState
{
Stateless = 0,
CreditCardDetailsExpired = 100,
PaymentNotice = 200,
PaymentFailure = 300,
CanCalculateFirstPayment = 600,
PaymentChangeNotified = 1000,
DefaultState = Stateless,
}



The code above is the kinds of state that our customer can fall into, in our scenario. No let us see the State engine implementation : First how to we fire an event to our state handlers that need to consume the events and do other processing based on these event/state that was raised. We need a delegate at first :



public delegate void CustomerStateUpdate(object source, StatusChangeEventArgs eventArgs);



Now we have successfully defined our delegate that serve as the template of our event handler. Remember, we are handling different customer state asynchronously, that is, the application or service that send us the customer object will not know about our processing and it wont wait for results.

Now we need to implement the state Publisher, that is the class that scan a customer object, fire the CustomerStateChangeEvent, and also registers interested subscribers to the state event. Here is a simple structure :



public class CustomerStatePublisher
{
public event CustomerStateUpdate CustomerStateEvent;
StatuChangeEventArgs eventArgs;
Customer customer;

public CustomerStatePublisher(Customer customer, StatusChangeEventArgs eventArgs)
{
this.eventArgs = eventArgs;
this.customer = customer;
}

public void AddSubscriber(CustomerStateUpdate subscriber)
{
CustomerStateEvent += subscriber;
}

public void RemoveSubscriber(CustomerStateUpdate subscriber)
{
CustomerStateEvent -= subscriber;
}

public void OnCustomerStateChanged(CustomerState customerState)
{
//We are not processing stateless customer
if (customerState == CustomerState.Stateless)
return;

if (null != CustomerStateEvent)
{
eventArgs.CustomerState = customerState;

//CustomerStateEvent(this.customer, eventArgs);

Delegate[] customerStateHandlers = CustomerStateEvent.GetInvocationList();

foreach (Delegate handler in subscriptionStateHandlers)
{
CustomerStateUpdate eventHandler = (CustomerStateUpdate)handler;
eventHandler.BeginInvoke(this, eventArgs, new AsyncCallback(AsyncReturn), eventHandler);
}
}
}

private void AsyncReturn(IAsyncResult result)
{
CustomerStateUpdate eventHandler =
(CustomerStateUpdate)result.AsyncState;

eventHandler.EndInvoke(result);
}

public void ProcessCustomerState()
{
RaiseStateChangedEvent(customer.CanCalculateFirstPayment());
RaiseStateChangedEvent(customer.CanCreatePendingPayment());
RaiseStateChangedEvent(customer.CheckCreditCardState());
RaiseStateChangedEvent(customer.OweMoney());
}

public void RaiseStateChangedEvent(CustomerState customerState)
{
if (customerState != customerState.Stateless)
OnCustomerStateChanged(customerState);
}

}



The class structure above is very simple to understand, so i will just point out where the asynchronous functionality is our code. The OnCustomerStateChanged method of this class calls all the registered subscriber to this event asynchronously, by getting the invocation list from the CustomerStateEvent (CustomerStateEvent.GetInvocationList();) iterating through it and call the BeginInvoke asynchronously, at this point, in our real world implementation of this, we should just detach from our caller service, and allow the asynchronously operations to run.

Now, since we have fully defined our CustomerStatePublisher class, we need to fully understand how we are going to register subscribers, and how we will begin, processing of our asynchronous state machine. The following code describe how we will register a subscriber to the CustomerStatePublisher, and how we will begin state processing :




//Create an instance of the Customer StateChangeEvent
CustomerChangeEventArgs eventArgs = new CustomerChangeEventArgs();

//Create an instance of the customer state publisher
CustomerStatePublisher publisher = new CustomerStatePublisher(customer, eventArgs);


publisher.AddStateObserver(new CustomerStateUpdate(StateHandler.CalculateFirstPayment));
publisher.AddStateObserver(new CustomerStateUpdate(StateHandler.PendingPaymentChanged));
publisher.AddStateObserver(new CustomerStateUpdate(StateHandler.CreatePendingPayment));
publisher.AddStateObserver(new CustomerStateUpdate(StateHandler.TrialWillExpireNotification));
publisher.AddStateObserver(new CustomerStateUpdate(StateHandler.CreditCardExpiryNotification));
publisher.AddStateObserver(new CustomerStateUpdate(StateHandler.FreeServiceNotice));

publisher.ProcessState();



The rest of the code is to define the subscribers, that is the StateHandlers that handles the state based on the state it can handle. A simple example is an implementation of one of the state handler.



public void CustomerCreditCardExpire(object source, CustomerChangeEventArgs eventArgs)
{
if (eventArgs.CustomerState != CustomerState.CreditCardDetailsExpired)
return;

//Execute statebased functionality here.
}



Having done the following, when control hits the publisher.ProcessState(); method, the whole state processing begins and a befitted state handler is found, the publisher now delegate the handler to handle the state. I would require more suggestions from you all. Thanks.

No comments: