ManualWorkflowSchedulerService and DelayActivity

Damir Dobric Posts

Next talks:

 

    

Follow me on Twitter: #ddobric



 

 

Archives

While implementing Windows Workflow (WF) applications, there are situation when the workflow has to be scheduled manually. By default one workflow is scheduled by using DefaultWorkflowSchedulerService. Additionally to default scheduler, Windows Workflow provides the ManualWorkflowSchedulerService.
The Manual Scheduler service is implemented to schedule the workflow in one thread only. This is very useful when you want strictly to control the number of threads in your application.
If you are asking yourself now, what specific scenario this could be, just think about workflow hosting in IIS environment. Because IIS has limited number of threads which can be allocated, running of the workflow within default scheduler could result in an implicit deadlock. Be sure what scheduler is used if the workflow is hosted in IIS or some similar host. One good example which describes differences between schedulers can be found in Scott's Ode2Code blog.

Following code shows how to start the workflow by using of Manual-Scheduler:

WorkflowRuntime runtime = new WorkflowRuntime();

ManualWorkflowSchedulerService manualScheduler =
new ManualWorkflowSchedulerService();

runtime.AddService(manualScheduler);

WorkflowInstance instance =
runtime.CreateWorkflow(
typeof(SomeWorkflow));

instance.Start();
manualScheduler.RunWorkflow(instance.InstanceId);


This code shows how to do the same thing with the Default-Scheduler:

WorkflowRuntime runtime = new WorkflowRuntime();

WorkflowInstance instance =
runtime.CreateWorkflow(
typeof(SomeWorkflow));

instance.Start();

So, if you use Manual Scheduler it is likely that the workflow will be executed on the same thread, which is none thread-pool thread. The Manual Scheduler is designed to do that, but there are some situations when this scheduler executes the workflow on more than one thread too. To explain this, imagine you have a workflow with external event handling. This could be for example, one delay-activity. In such cases, when the delay time is expired the activity right after delay-activity will be invoked on the different thread, which is thread-pooled. In general it is to expect, that external event handling most likely always implements some kind of listening on different thread.
If you decided to use Manual Scheduler, because you want to limit number of threads, be aware of this behavior.

There is at least one more important thing about Delay-Activity you should know. When this activity is used with Manual Scheduler you may notice that the delay-activity does not work. It means, the expected time limit seems to never be expired. To solve this problem, the Manual-Scheduler Service has additional constructor, which can be used to activate so called Active Timers:


ManualWorkflowSchedulerService
scheduler =
new ManualWorkflowSchedulerService(
true);

I agree that this parameter is not well documented. But, don't be confused with the name of this parameter. As I sow it first time, I was like "Now I have to dig in the theory of relativity". The good news is that scheduler internally does nothing than registers a well known timer callback handler as shown below:


TimerCallback
timerCallback = new TimerCallback (OnTimerCallback);

When using manual scheduling, note that the method RunWorkflow() returns  after the workflow is persisted or enters a Delay-Activity. In this case you have to implement the synchronization by yourself as shown in the following example:


// How to signal that the WF is completed.
m_Runtime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs e)
{
  
  waitHandle.Set();
};

instance = m_Runtime.CreateWorkflow(. . .
);

instance.Start();

// WF is completed.
bool r = m_Scheduler.RunWorkflow(instance.InstanceId);

// Here we wait on WF to be completed
waitHandle.WaitOne();

Visit: www.daenet.eu, www.daenet.de, www.daenet.nl, www.daenet.ba.


Posted Dec 10 2007, 11:31 PM by Damir Dobric
Filed under:

Comments

Damir Dobric wrote re: ManualWorkflowSchedulerService and DelayActivity
on 04-01-2008 16:06

I would also recommend this article: blogs.msdn.com/.../583392.aspx

Damir Dobric wrote re: ManualWorkflowSchedulerService and DelayActivity
on 04-03-2008 8:30

Be also aware of this: support.microsoft.com/.../821268

garrone wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-18-2008 23:06

I have read your article, and it does sounds interesting. However, I have a problem which seems to be close to what you wrote here, and you might have an ideea an give me a hint:

I have an Application which hosts a thread pool which is supposed to run some sequential workflows. I am using ManualWorkflowSchedulerService(true). My problem is that when some workflow is "persisted", when waked up, it runs into a different thread - other than the ones from my thread pool. Is there any way I can "force" the runtime to pick one thread from my own thread pool?

Bests.

Damir Dobric wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-18-2008 23:55

If you redehydrated persisted workflow on the same thread it was running at the moment of persisting, the you can run it on the same thread by using of manual scheduler service.

However, this scenario seems to be a bit unusual, because theoretically it will and should never  be the same thread. Persistence is also done for purpose of keeping of WF session state and it should survive host crash. What will you do if the host is restarted and WF then redehydrated . In this case there is even no theoretical solution.

Hope this helps...

garrone wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-19-2008 10:24

Yes, I am using manual-scheduler to start the workflows. My problem is after the workflow is persisted into db, and then it need to be `waked` up - the scheduler uses another thread than from my thread-pool. I want to decide on what thread the revived workflow should be executed.

This behaviour looks similar with default-scheduler, but my problem is I want to manage the waiting-queue too (it has to be stored on db, etc).

Damir Dobric wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-19-2008 10:52

I’m concerned about that design, because:

1. When the WF is persisted on Thread T1. What should happen with that thread as long the WF is in persisted state. To keep it opened is not a good idea. If you abort it, you will never again be able to do reload anything in that thread, because it does not exist anymore.

2. What when the host is started again? The there is no thread which has previously hosted persisted WF.

garrone wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-19-2008 11:29

No, I think there's a misunderstanding: I have a thread pool with threads T1, T2, T3 which they will always "be there". If the host is restarted, there will be another T1, T2, T3. I don't care if they are the same or not. I also don't care if the workflow was executed first on T1, then is scheduled on T2, as long as they are threads from my thread pool. They are just worker threads, and I want to avoid as much as I can the creation of new threads. The application need to be fast. On my test, the framework decides to create a new thread (T4). Assuming we have 100 threads in my thread-pool, and all of them are executing workflows which need to be persisted at some point, and then all of them are resumed at the same time, we end up having 200 threads instead of 100.

I just want to know if it's possible to hook the `wake up` event and schedule on one of my own threads the resumed workflow.

Andreas Erben wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-19-2008 18:39

To garronne:

It is difficult to guess about what might cause the additional threads to be created.

Here is how I understood your scenario:

You do manage your own thread pool, you do not use the .net thread pool at all.

I wonder what your implementation does already.

Are you sure you are not causing additional threads to be created by something else? what do you use in your workflows?

If you use the manual scheduler service, then you execute on the thread that is actually running.

Meaning, you need to look at the loaded workflows and run each of them individual from the specific thread you want it to run on.

how do you start your persisted threads now?

An interesting blog post in that context:

codeidol.com/.../Running-a-WF-Program-Instance

Damir Dobric wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-19-2008 18:49
Andreas Erben wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-20-2008 11:36

regarding my previous comment to garronne....

I see you used UseActiveTimers... my comment did not take that into consideration.

garrone wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-23-2008 17:50

Hi! :)

I have found a way to solve that issue. I had to inherit the WorkflowSchedulerService base class. The only 2 methods needed to be overriden are the `Schedule` ones. The first one is called when the workflow is started - which is executed in one of my threads as the workflow is started from there, and the second one (which provides a callback method) is executed in workflow runtime thread, but as I can get my own thread pool and start the execution of the rest of the workflow in it.

Both links were helpful! :) Thanks again.

Damir Dobric wrote re: ManualWorkflowSchedulerService and DelayActivity
on 06-23-2008 17:56

:)

http://www.louisvuittonreplicago.com wrote re: ManualWorkflowSchedulerService and DelayActivity
on 09-09-2012 1:50

This has been quite  open-handed of people like you to offer freely what exactly many people could possibly have supplied as an electronic book to get some profit for themselves, chiefly seeing that you could possibly have done it in the event you decided. The tactics as well acted to provide a good way to be sure that the rest have the identical dream the same as my personal own to find out very much more pertaining to this condition.http://www.louisvuittonsau.com

developers.de is a .Net Community Blog powered by daenet GmbH.