Richard Searle's Blog

Thoughts about software

Archive for March, 2011

Recursive PartialFunctions for Choreography

Posted by eggsearle on March 28, 2011

The core of an Actor is the receive function, which is a PartialFunction over the expected inputs to the actor. The remainder of actor is largely boilerplate, concerned with implementation details. Our choreography DSL must be built around the process of building a PartialFunction that implements the composite service.

An interaction with a sub-service might be expressed as a function (A)=>CorrelationID which represents starting of a request/response MEP over the JMS queue. This function exposes an implementation detail (the CorrelationID) and does not capture the type of the expected response. That type would allow Scala to automatically provide useful service, such as automatic wiring via implicit values. It also provides type safety and documentation.
The response once received will be processed by some function, which can be expressed as part of the sub-service function (A)=>(R)=>X, where R is the type of the response and X is the final result. We have now captured both types that participate in the sub-service interaction and tied it into the workflow that it drives. The key question is then:What is X? In general, the consuming function will perform further sub-service interactions with their own consuming functions! X is thus a PartialFunction that returns values that have type X. Such recursion must eventually terminate with the final result of the composite service. A special type will be used for that purpose, using the Option idiom

trait RPF extends PartialFunction[CI, Any=>RPF]
trait Lookup[A,R] {
 def apply(arg:A)(fn:R =>RPF):RPF = ...
}
case class Result[A](value:A) extends RPF{...}

The composite workflow can now be written as

object SingleLineBalance{
   def apply(pn:Num)(implicit acctLook:Lookup[Num,Acct],  balLook:Lookup[Acct,Bal]) =
   {
         acctLook(pn){balLook(_)(Result(_))}
   }
}

The Lookups representing the sub-services are specified as implicits so they can be “automatically wired” at the point the object is used. Note that SingleLineBalance is not itself the workflow but rather returns a function that is the implementation.

It can be read:

  • Create an RPF to evaluate the composite service for phone number pn
    The RPF will be evaluated elsewhere and at some time in the near future (generally within  an actor)
  • When the RPF is evaluated make a request to the acctLook sub-service with the pn
  • When the account number response is received, make a request to the balLook sub-service with that value
  • When the balance response is received, return the balance wrapped in a Result

This is a faithful representation of the original business process, with minimal boilerplate.

Posted in Akka, Scala | Leave a Comment »

Contemplating an Akka choreography implementation

Posted by eggsearle on March 27, 2011

A common SOA design pattern decomposes a service into multiple references to other services, referenced via request/response JMS interactions.  The implementation commonly uses XPDL, BPEL or some proprietary variant running on a workflow engine such as Tibco BusinessWorks or BEA(Oracle) Aqualogic Service Bus.

Such services commonly require some state (e.g. summing of balances) and non trivial logic (implementing business rules). That makes them difficult to implement using data flow oriented tools such as Apache Camel or Spring Integration. An actor implementation is a much better match to the requirements and the general model behind such composite services.  The service can be long running (1-20 seconds) essentially mandating the usage of a reactive actor to avoid holding a thread. There are many actor implementations that could be considered. Akka actors are a particularly good match

  1. Runs on Scala, allowing reuse of the entire Java ecosystem and existing application code base
  2. Small footprint, reactive actors
  3. Trivial integration with Camel and hence to a wide range of integration mechanisms (JMS, AMQP, REST, etc)

A simple service might support a IVR system that reads back the balance of the account associated with the callers phone number. The IVR sends a JMS message containing the phone number and expects a JMS message containing the balance in response. Two sub-services are referenced to map number to account and account to balance. Each sub-service listens on a JMS queue and replies with the required data.

An interaction with a  sub-service requires the sending of a JMS message containing the request data and a Correlation ID that will be included in the reply message so it can be tied back to originator.  The actor implementing the composed service would then have the skeleton form

class CompositeService extends Actor {
def receive = {
  case (CorrelationID,Acct) => //invoke Acct -> Balance service
  case (CorrelationID,Balance) => //reply to IVS application
 }

Where each case matches the contents of the JMS reply message from the external service.

The service reference to map the phone number to account needs to be performed by the actor so that it does not block the logic that handles the initiating message from the IVR system. We then have

class CompositeService extends Actor {
var replyTo:Destination = _
def receive = {
  case (Destination, Number) => //invoke Number -> Account service
  case (CorrelationID,Account) => //invoke Acct -> Balance service
  case (CorrelationID,Balance) => //reply to IVS application
}

Where Destination is the JMS ReplyTo address of the IVR systems. The actor has state (the replyTo field) and new instance must thus be created for each invocation by the IVR system.

The reply from each sub- service invocation is sent to the actor instance for processing.

The above is certainly workable, but has some disadvantages

  1. Mandates usage of actors
    Unit testing would be easier with a serialized implementation.
  2. Mandates the usage of Akka
  3. Difficult to map more complex orchestration into this structure.
    The primary force behind the usage of XPDL, BPEL, etc was the desire to move the orchestration definition into the hands of business process designers.

The goal is to provide a library with which such orchestrations can easily be implemented.  It is unlikely to be directly accessible to business process designers since it requires some Scala knowledge. Compiling a representation such as XPDL into the Scala implementation should be straightforward, providing as such support to the business process designers as the commercial implementations.

Posted in Akka, Scala, Uncategorized | Leave a Comment »