BizTalk Orchestration Throttling Pattern

I’m currently architecting a project where one of the requirements is to limit the number of concurrent calls to a web service. I’d covered a similar topic in a previous post, and outlined two ways one could try and configure this behavior.

First, you could limit the number of simultaneous connections for the SOAP adapter by setting the “maxconnections” setting in the btsntsvc.exe.config file. The downside to this mechanism is that if you have many messages, and the service takes a while to process, you could timeouts.

The second choice is to turn on ordered delivery at the send port. This eliminates the timeout issue, but, really slows processing. In our case, the downstream web service (a FirstDoc web service that uploads documents to Documentum) is fairly CPU intensive, and may take upwards of 200 seconds to run (which is why I also asked the developer to consider an asynchronous callback pattern), so we need a few calls happening at once, but not so many that the box collapses.

So, Scott Colestock recommended I take a look at the last issue of the BizTalk HotRod magazine and review the orchestration throttling pattern that he had expalined there. Unlike the two options mentioned above, this DOES requirement development, but, it also provides fairly tight control over the number of concurrent orchestrations. Since Scott’s article didn’t have code attached, I figured I’d rebuild the project to help our developer out, and, learn something myself.

The first step was to define my two BizTalk message schemas. My first is the schema that holds the data used by the FirstDoc web service. It contains a file path which the web service uses to stream the document from disk into Documentum. I didn’t want BizTalk to actually be routing 50MB documents, just the metadata. The second schema is a simple acknowledgement schema that will be used to complete an individual processing instance. Also, I need a property schema that holds a unique correlation ID, and the instance ID of the target convoy. Both properties are set to MessageContextPropertyBase since the values themselves don’t come from the message payload but rather, the context.

The second step was to build a helper component which will dictate which throttled instance will be called. Basically, this pattern uses convoy orchestrations. The key is though, that you have multiple convoys running, vs. a true singleton that processes ALL messages. The “correlation” used for each convoy is an instance ID that corresponds to a number in the numerical range of running orchestrations allowed. For instance, if I allowed 10 orchestrations to run at once, I’d have 10 convoy orchestrations, each one initializing (and following) an “InstanceID” between 1-10. Each of my calling orchestrations acquire a number between 1-10, and then target that particular correlation. Make sense? So I may have 500 messages come in at once, and 500 base orchestrations spin up, but each one of those target a specific throttled (convoy) orchestration.

So my helper component is responsible for doling out an instance ID to the caller. The code looks like this:

[Serializable] public static class RoundRobinHelper { //member variable holding current selection private static int roundRobinSelection = 0; private static object sync = new object(); /// /// Thread-safe retrieval of which /// orchestration instance to target /// /// public static int GetNext() { const int maxInstances = 3; lock (sync) { //increment counter roundRobinSelection++; //if we've reached the limit, reset if (roundRobinSelection == maxInstances) { roundRobinSelection = 0; } } return roundRobinSelection; } }

Notice that because it’s a static class, and it has a member variable, we have to be very careful to build this in a thread safe manner. This will be called by many orchestrations running on many threads.

Once this component was built and GAC-ed, I could build my orchestration. The first orchestration is the convoy. The first receive shape (which is direct bound to the MessageBox) initializes the “instance ID” correlation set. Then I have a loop which will run continuously. Inside that loop, I have a placeholder for the logic that actually calls Documentum, and waits for the response. Next I build the “acknowledgement message”, making sure to set the “Correlation ID” context property so that this acknowledgement reaches the orchestration that called it. I then send that message back out through a direct bound send port. Finally, I have a receive shape which follows the “Instance ID” correlation set (thus defining this orchestration as a convoy).

  

Next, we have the orchestration that spins up for EVERY inbound message. First, it receives a message from a port bound to a file receive location. Next, within an Expression shape, I call out to my “round robin” helper component which gives me the next instance ID in the sequence.

ThrottledInstanceId = BizTalkPattern.OrchHelper.RoundRobinHelper.GetNext();

I then make sure to create a new message with both the “Correlation ID” and “Instance ID” context properties set.

//create message copy Metadata_Output = Metadata_Input; //set convoy instance ID Metadata_Output(BizTalkPattern.BizTalkBits.InstanceId) = ThrottledInstanceId.ToString(); //set unique ID using orchestration instance identifier Metadata_Output(BizTalkPattern.BizTalkBits.CorrelationID) = BizTalkPattern.BizTalkBits.ProcessAllMetadataFiles (Microsoft.XLANGs.BaseTypes.InstanceId);

Finally, I send this message out (via direct bound send port) and wait for the acknowledgement back.

  

So what I have now is a very (basic) load balancing solution where many inbound messages flow through a narrowed pipe to the destination. The round robin helper component keeps things relatively evenly split between the convoy orchestrations, and I’m not stuck using a singleton that grinds all parallel processing to a halt.  Running a few messages through this solution yields the following trace …

If I look in the BizTalk Administration Console, I now have three orchestrations running at all times, since I set up a maximum of three convoys.  Neat.  Thanks to Scott for identifying this pattern.

Any other patterns for this sort of thing that people like?

Technorati Tags:

11 Responses to “BizTalk Orchestration Throttling Pattern”


  1. 1 Patrick Wellink May 19, 2008 at 11:36 pm

    Have a look at my blogpost here :

    http://bloggingabout.net/blogs/wellink/archive/2007/02/12/limit-the-number-of-instances-of-any-biztalk-service.aspx

    or source at :

    http://www.codeplex.com/InstanceController/Release/ProjectReleases.aspx?ReleaseId=1863

    It’s my implementation of an “Instance controller”. See if it will work for your scenario…… I think it does the same.

    There is some work in there preventing the convoys of stopping if an outbound message get’s suspended and effectively stopping the entire convoy…

  2. 2 Richard Seroter May 20, 2008 at 8:00 am

    Thanks Patrick. I actually found your post when I was digging around. Any core differences between what you’ve built and what I demonstrated above?

  3. 3 Mike Stephenson May 20, 2008 at 2:00 pm

    Hi Richard,

    As usual another good post, just like to comment on one thing about your design though.

    If you had this running in a multi server environment then your singleton style implementation around generating your round robin instance id would mean potentially all servers will be counting from 1 each time and this means if you had 6 servers all processing a similar load the likelyhood is they could all pipe their message to the same throttled orchestration instance.

    As result you will be throttling but you could be well below your optimal performance.

    It might be worth considering using a random number between 1 and your max number of instances where you will probably get a more even distribution of messages across the throttled orchestration instances in both single and multi server environments

    Another benefit is it would allow you to remove the locking required in your helper class which as you rightly point out is the type of code which is usually a little higher risk to encounter a problem if not quite implemented correctly or changed by a developer who hasnt considered the multi threading aspects.

    Hope this is useful
    Mike

  4. 4 Richard Seroter May 20, 2008 at 6:26 pm

    Hey there Mike,

    Good suggestions. Scott mentioned the multi-server idea in his article, and you’re right, I’d have to pick a “max instance” which was acceptable if BOTH servers sent that many messages. Your concept of a random number (up to the max) is a pretty good idea.

  5. 5 Patrick Wellink May 22, 2008 at 10:35 am

    Well I am not really sure how much they differ.

    The instance controller is a deployed orchestration that can limit every outgoing message. It doesn’t know what it’s limiting.

    So it’s a deploy once limit all solution.

    For sure in the inplementation of your orchestration you have to wrap stuff up and send it to the controller, so you have to do little work for that.

    If you could send me your solution I could have a look at it. I am very eager to find the best solution to my problem of a year ago.

    The problem was we had to talk to Axapta via a webservice. And only 10 licences were bought. So we could have 50 Services hosted at Axapta and only 10 connections.

    Then batches were spun off and we had to keep the maximum number of connections to about 8 (Keep some open for the interactive users).

    So we had to limit outgoing instances over all those services.
    Complicated stuff alltogether…..

  6. 6 Mike Stephenson May 23, 2008 at 2:54 am

    Patrick

    Did you experiment with the solution of controlling this with the max connections element in the configuration file. If you configured each server in your group to only be allowed 5 connections to the load balanced address of the server hosting your Axapta web services and then configured the BizTalk host which your send ports run in to only run on 2 servers you should not be able to make more than 10 concurrent connections and still have fail over.

    This should also require no coding changes

    The below link discusses it a bit.
    http://msdn.microsoft.com/en-us/library/aa561380.aspx

    If you have tried it would be interested to know how you got on

    HTH
    Mike

  7. 7 Tommy July 12, 2008 at 12:31 pm

    Hi, Richard, could you please share the source code for this pattern, I really appreciate your help…

  8. 8 Richard Seroter July 15, 2008 at 9:35 am

    Hey Tommy,

    Unfortunately this was written for (and branded with) my company in mind. Hopefully you’d be able to recreate the solution using the steps in the post. If you run into any hurdles, just let me know.


  1. 1 What I Learned Yesterday 12 « Ben Runchey’s Integration Dev Blog Trackback on May 27, 2008 at 12:14 pm
  2. 2 BizTalk Orchestration Throttling Pattern « Noocyte’s Weblog Trackback on July 1, 2008 at 12:14 am
  3. 3 max orchestration | keyongtech Trackback on January 18, 2009 at 8:46 am

Leave a Reply




Disclaimer

Entries and comments here do not necessarily reflect the opinions, attitudes, and statements of my employer, my friends, or anyone associated with me.

Syndication

Publications

Order my new book SOA Patterns with BizTalk Server 2009 (Amazon.com, Packt Publishing)

Contact Me

Categories

Twitter Feed

Blog Stats

  • 222,744