Workflow persistence and bookmarks as a workflow failover

1.2k views Asked by At

I have set of custom activities, which are used in complex workflows.

I would like to make them (custom activities) persistable without having workflow in an idle state. It should be kind of failover system, so whenever something goes wrong during execution of a workflow it can be either:

  • paused by a user (in anytime) and resumed later from the bookmark/point it was paused (for example user has noticed that an external system is down and he wants to pause the workflow for time being).
  • in case of an unhandled exception we can restart execution from last bookmark/point in time
  • stop of WorkflowApplication host can happen anytime and we can restart execution from last bookmark/point in time

I've worked for few days with workflow persistance, but I am not sure if I can achieve my goal with it. Why?

  • I could use blocking bookmarks in each custom activity, but blocking a workflow and restarting it just for purpose of having it persisted doesn't look promising.
  • I could use notblocking bookmarks, but I was not able to see them in database and resume from it.

Can you please advice me, it workflow bookmarks are the way to go here?

I see some light in notblocking bookmarks, but I cannot persist them and resume later on. Can you please give me some hints how to persist a nonblocking bookmark for later resume?

Edit:

In wf3 there was an attribute PersistOnClose which would be enough for my requirement. in wf4 it was replaced with Persist activity, which could also be useful, however I do not want to have extra activities in my already complex workflows.

Ideally, it would be great to be able to execute context.RequestPersist(callback) from NativeActivityContext , however this method is internal (and everything what is inside it is not visible outside of original assembly.

2

There are 2 answers

0
Michał Szkudlarek On BEST ANSWER

Here is what I came with:

  • Non-blocking bookmarks are not an option. Although a non-blocking bookmark does not prevent the creating activity from completing but it also does not cause the workflow instance to become idle - which means it will not be persisted. Non-blocking bookmarks are discarded once the activity (which created it) completes. This bookmark can be resumed only if creating activity has not completed.
  • Using PersistOnCloseAttribute is not an option, because I'm using WF4 and this attribute is only .NET 3.x WF.
  • Blocking bookmarks cannot be used, because they block execution of a workflow, which is not desired.

The solution is to use Persist activity in each custom made activity (has to extend NativeActivity which can schedule child activities):

//class field
Activity childActivity = new Persist();

In order to make it work, it has to be added to metadata as ImplmentationChild:

protected override void CacheMetadata(NativeActivityMetadata metadata)
{
     base.CacheMetadata(metadata);
     metadata.AddImplementationChild(this.childActivity);
}

The last thing is to schedule child activity from Execute method (doesn't matter where, persistence will happen only after calling activity is completed*).

protected override void Execute(NativeActivityContext context)
{
    //...
    context.ScheduleActivity((Activity)this.childActivity);
}

In order keep the workflow persisted after unhandled exception, this piece of code have to be added to WorkflowApplication:

 application.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
 {
      return UnhandledExceptionAction.Abort;
 };

*return from the Execute method doesn't necessarily mean that the activity is "completed" - i.e. there are blocking bookmarks inside activity (see drawbacks below).

There are few drawbacks of this solution:

  • Solution keeps only one state of the workflow (the last state).
  • Persistence can happen only when activity has completed. Which means that persist/resume cannot be done from the middle of an activity.
  • It does not work with parallel loops/sequences - activities from parallel loop/sequence are persisted after entire parallel thing is completed. It works correctly with regular loops/sequences.
  • Blocking bookmarks have a huge influence on this solution (if they are created in creating activity or in other child activities of creating activity). They cause that activity is not completed, even though Execute method returned. Eventually Persist will execute (either after completion of activity or before going into idle state).
0
Vivek On

If i understand you question correctly then, you have below requirements.

  1. Persistence and recovery of workflow.
  2. User can pause and resume.
  3. In case of any exception, workflow persisted and resume from next activity.

You can approach using below steps.

  1. You can use WF + WCF service to execute and host your workflow.
  2. Add persistence and tracking with a data base like Sql server, if you are using oracle then can use Devart.
  3. Configure ControlEnpont to pause and resume.
  4. Use try/ Catch and persistence activity wisely to handle exception.

in case of any issue and customization required discussed same.:) as I have developed workflow like similar like yours.