Platinum Partner
architects,high-perf,performance,tips and tricks

Don’t Use Workflow Bookmarks in Transaction Scopes

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 {{ articles[0].authors[0].realName }}, DZone MVB. (source)

Opinions expressed by DZone contributors are their own.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}