Performance Zone is brought to you in partnership with:

Sasha Goldshtein is a Senior Consultant for Sela Group, an Israeli company specializing in training, consulting and outsourcing to local and international customers.Sasha's work is divided across these three primary disciplines. He consults for clients on architecture, development, debugging and performance issues; he actively develops code using the latest bits of technology from Microsoft; and he conducts training classes on a variety of topics, from Windows Internals to .NET Performance. You can read more about Sasha's work and his latest ventures at his blog: http://blogs.microsoft.co.il/blogs/sasha. Sasha writes from Herzliya, Israel. Sasha is a DZone MVB and is not an employee of DZone and has posted 197 posts at DZone. You can read more from them at their website. View Full User Profile

Don’t Use Workflow Bookmarks in Transaction Scopes

12.24.2012
| 1875 views |
  • submit to reddit

It’s been a while since I posted about a workflow-related bug, and it’s not because of my mad WF skillz – it had more to do with Manu’s expertise in the big WF project I’m involved in. The following bug slipped through the cracks and is worth sharing.

One of our custom activities sends a query to the user and waits for a response. This can take days – a human operator is not always available to answer the question, and some questions may require escalation. In one of our recent workflows, two queries had to be sent simultaneously, and the first query answered should cancel the other. This is the Pick activity’s natural habitat. What we also needed is to issue one of the queries within a transaction to record its results transactionally. This leads to the following workflow, with the transaction scope marked in a red box:

image

Unfortunately, running this workflow as part of our integration tests, we discovered that the first branch is never executed – in fact, it never returns from the Delay activity. However, the tracking information seemed to suggest that it is not cancelled, either – so it couldn’t be the case that the second branch has already completed.

It turns out that our activity’s implementation relies on a bookmark – it creates a bookmark and waits for an external mechanism (a WCF service host) to resume it from the bookmark.

public class QueryActivity : NativeActivity
{
    protected override bool CanInduceIdle
    {
        get { return true; }
    } 
    protected override void Execute(
        NativeActivityContext context)
    {
        context.CreateBookmark(
            "MyBookmark", BookmarkSet);
    }
 
    private void BookmarkSet(
        NativeActivityContext context,
        Bookmark bookmark, object value)
    {
        Console.WriteLine("Done");
    }
}

Creating a bookmark and waiting for resumption in a transaction scope leads exactly to the situation described above, and it is a bad idea anyway – a transaction isn’t supposed to last several days.

To solve the problem, we will need to use a custom mechanism to bring the workflow transactionally to a point where it has recorded the query answer (by resuming the bookmark, persisting the workflow within the external transaction, and then letting it proceed). This is how a seemingly simple task turned out to be quite complex.



Published at DZone with permission of Sasha Goldshtein, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)