Richard Searle's Blog

Thoughts about software

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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: