Long-Running Singleton Orchestrations
Singleton orchestrations usually involve correlated receives within a loop. This design pattern is often necessary for batching, maintain ordered processing, or throttle downstream work. The singleton design itself normally doesn’t raise any performance concern. It is when the looping condition keeps the orchestration alive for days or weeks, you may then notice gradual degradation in performance. The reason? As orchestration loops, it is possible for different objects to accumulate and eventually impact performance.
Since BizTalk Server 2004, the product team has made a number of fixes to address this issue, for example Q912276 for BizTalk 2004. So far all of these fixes are already included in BizTalk Server 2006. Even with these optimizations, one can imagine that small artifacts can still add up over extended period of time.
During your design phase, you should make sure that all objects you created are cleaned up when they are no longer needed. As additional safety net, you should also consider adding logic to limit the lifespan of your singleton orchestration. The mechanism would vary based on your business scenario and you should test the solution thoroughly to make sure the controlling logic does not leave behind discarded messages.
Most straightforward design would be to employ a counter with your loop. This often is not practical as you may not have control over how many messages arrive in a batch. If you terminate an orchestration when some messages are delivered to the engine but not yet processed, these messages will be suspended instead of being picked up by the new instance of the singleton orchestration.
Another design approach is to terminate an orchestration instance only when it is idle. With this design, you will be adding a Listen Branch into the loop. On one branch you will be receiving the correlated message as before. On the other branch, you’ll have a Delay Shape followed by logic to exit the loop. The concept is simple. When messages are flowing in, execution path will stay on the receiving side of the Listen Branch. When message delivery stops, eventually you will exceed the value of the timer object in the Delay Shape. Execution path moves to the delay branch and you can simply set a Boolean variable in an Expression Shape after the Delay to exit the loop. This orchestration instance then completes and next message that is delivered to the orchestration engine starts off a new instance of the orchestration. You are free to pick an idle period that works for your business scenario.
No matter which design you choose, the key idea here is that while diamonds are forever, orchestration instances shouldn’t be.