Philippe Sillon

Hi,

For workflow : Code -> Delay (1 hour) -> Code

On Idle, I persist workflow on SQL Server. My question is "what is the better way to re-start workflow after 1 hours" to continue workflow execution.

Thank you

Philippe.



Re: Windows Workflow Foundation Delay Activity -> long time running

Darren Headrick - MSFT

The delay activity was created for this very purpose, to allow an event to occur after a certain amount of time. Is there a particular reason why you are looking for another way of accomplishing this




Re: Windows Workflow Foundation Delay Activity -> long time running

Philippe Sillon

For following workflow Code 1 -> Delay (1 hour) -> Code 2
When workflow is idle, I setup application to persist it on SQL server and unload it. the problem is that Code 2 (after delay activity) is never execute. I think it's because workflow is unload and not executed.


private void button1_Click(object sender, EventArgs e)
{
WorkflowRuntime runtime = new WorkflowRuntime();

SqlWorkflowPersistenceService persistence = new SqlWorkflowPersistenceService("<connection string>");
runtime.AddService(persistence);
runtime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(runtime_WorkflowIdled);
runtime.WorkflowPersisted += new EventHandler<WorkflowEventArgs>(runtime_WorkflowPersisted);

runtime.StartRuntime();

WorkflowInstance instance= runtime.CreateWorkflow(typeof(Workflow1));
instance.Start();
}

void runtime_WorkflowPersisted(object sender, WorkflowEventArgs e)
{
Log("WorkFlow Persisted");
}

void runtime_WorkflowIdled(object sender, WorkflowEventArgs e)
{
Log("WorkFlow Idled");
e.WorkflowInstance.Unload();
}

void runtime_WorkflowLoaded(object sender, WorkflowEventArgs e)
{
Log("WorkFlow Loaded");
}

private void Log(string text)
{
Console.WriteLine("-->"+text);
}





Re: Windows Workflow Foundation Delay Activity -> long time running

AlanJamesSmith

Hi,

There's a property on the SqlWorkflowPersistenceService called UnloadOnIdle. Try setting this to True before you call AddService(). You can leave the Console.WriteLines in the methods, but comment out the e.WorkflowInstance.Unload() call. You should see the workflows being persisted to the SQL database, and you can query for them, there.

Try this with one minute delays first, and see what happens. In the DB, you should see a column on one of the tables with the time the timer will expire. The Sql Persuistence Service uses this to reload the workflows at the appropriate time. (I think it uses UTC time here).

Regards,

Alan Smith





Re: Windows Workflow Foundation Delay Activity -> long time running

Philippe Sillon

Thank a lot for your response and you right, NextTimer indicate when workflow must be reloaded. And activity is start :

==> Code A : e09f0d06-963d-49f5-a2e9-cd33ee3f1dec
-->WorkFlow Idled : e09f0d06-963d-49f5-a2e9-cd33ee3f1dec
-->WorkFlow Persisted : e09f0d06-963d-49f5-a2e9-cd33ee3f1dec
.... waiting....
-->WorkFlow Loaded : e09f0d06-963d-49f5-a2e9-cd33ee3f1dec
==> Code B : e09f0d06-963d-49f5-a2e9-cd33ee3f1dec
-->WorkFlow Persisted : e09f0d06-963d-49f5-a2e9-cd33ee3f1dec

Note : It's work with Unload method on Idle Event Handler. UnloadOnIdle is protected in SqlWorkflowPersistenceService (based on doc http://msdn2.microsoft.com/en-us/library/system.workflow.runtime.hosting.sqlworkflowpersistenceservice.unloadonidle.aspx#Mtps_DropDownFilterText
)

protected
internal override bool UnloadOnIdle (

  Activity activity
)
Other question :

Base on my test, If I start workflow 1 and close my application after workflow 1 is persist on DB. The Code B (the one after Delay activity) is not start until I start a new workflow (2) and leave application open until Code B execution : at this point code B for workflow 1 AND 2 will be executed.


Example : I start program to start workflow 1 :

==> Code A : 60ffe6d0-75f5-4cb1-afc6-d6ece5e7a502
-->WorkFlow Idled : 60ffe6d0-75f5-4cb1-afc6-d6ece5e7a502
-->WorkFlow Persisted : 60ffe6d0-75f5-4cb1-afc6-d6ece5e7a502

I close program at this point and I start new program instance to start workflow 2 and waiting complete execution :

==> Code A : 6b51f381-de8c-4ac6-9d60-888f1778d89d
-->WorkFlow Idled : 6b51f381-de8c-4ac6-9d60-888f1778d89d
-->WorkFlow Persisted : 6b51f381-de8c-4ac6-9d60-888f1778d89d
-->WorkFlow Loaded : 60ffe6d0-75f5-4cb1-afc6-d6ece5e7a502
==> Code B : 60ffe6d0-75f5-4cb1-afc6-d6ece5e7a502
-->WorkFlow Loaded : 6b51f381-de8c-4ac6-9d60-888f1778d89d
==> Code B : 6b51f381-de8c-4ac6-9d60-888f1778d89d
-->WorkFlow Persisted : 60ffe6d0-75f5-4cb1-afc6-d6ece5e7a502
-->WorkFlow Persisted : 6b51f381-de8c-4ac6-9d60-888f1778d89d

Code B of workflow 1 and workflow 2 are executed.


This mean that Code B of workflow 1 will be executed only when a Workflow 2 will reach same activity Not sure about logic .

Do you have any suggestion to resolve this issue : I prefer that code B of workflow 1 start when next timer will be reach. May be I need to implemente service

Thank a lot for your help.

Philippe










Re: Windows Workflow Foundation Delay Activity -> long time running

NDG

In my understanding, any workflowruntime using the same persistence service could pick up workf low 1.

So even if you throw away computer 1 and start the workflowruntime (with the same persistence service) on computer 2, computer 2 would pick up the idled flow.

If you want to start at next timer this would need an active workflowruntime on that persistence service, a windows service would be appropriate for this.

Above info is just from hearing and reading, I did not test it personally.






Re: Windows Workflow Foundation Delay Activity -> long time running

Darren Headrick - MSFT

Two things, first of all your going to want to set unload on idle to true, the way I did this was by using the constructor,

TimeSpan instanceOwnershipDuration = TimeSpan.MaxValue;
TimeSpan loadingInterval = new TimeSpan(0, 2, 0);

SqlWorkflowPersistenceService persistence =
new SqlWorkflowPersistenceService(
"Data Source=localhost;Initial Catalog=Store;Integrated Security=True;Pooling=False",
true, // UnloadOnIdle value
instanceOwnershipDuration,
loadingInterval );

As far as your second question, I was able to reproduce that and I going to ask around to a few of the other developers to see whats going on there, I'll post more info when I get it.






Re: Windows Workflow Foundation Delay Activity -> long time running

AlanJamesSmith

Hi,

It sould pick up the workflow when you start the hosting application again. Just make sure that you are making the call to StartRuntime(). If not, the runtime will only start when you create the next workflow. This may be the behaviour you are experiencing.

Regards,

Alan Smith





Re: Windows Workflow Foundation Delay Activity -> long time running

Darren Headrick - MSFT

The Runtime wont pick up workflows that are blocked, and the workflows left in the database with the delay are marked as blocked. It is possible to manually remove the entries that get left in the database through SQL, you could also do it progmatically but i'd like to learn a little more about your situation before I guide you along that path. I am curious why you are using persistence for a workflow like this. Generally the persistence service is used for a workflow which you want to be able to just close and then continue later. The behavior you are seeing is expected, the workflow gets stranded in the middle of a delay. Because that delay never gets to notify its caller it has completed, when the second workflow gets the event that a timeout has completed, it gets the workflows that are persisted and "continues" them, causing your behavior.

A question for you, is there a larger goal that you are trying to accomplish perhaps we can help you to model your scenario differently.






Re: Windows Workflow Foundation Delay Activity -> long time running

Philippe Sillon

Hi,

Thank a lot for all responses.

About the goal, I have an web site to order product. I would like to associate workflow on all order for a specific product (example : BlackBerry). This workflow must send email to creator of order 10 days after order creation date, to reminde an action (example : please contact this group to activate feature on your new Blackberry).

So when order is place, I start workflow for 10 days to send email. But I don't want to keep workflow in memory so I persist it on SQL server.. The question is what is the better way to wake-up workflow when timer is reach And I don't want to be dependent of other workflow execution... I would like that workflow that reach time to continue re-start 'it-self'... now I 'hope' that a second workflow will be executed to allow first workflow to continue..


Thank you again for your help. I want to implemente it from the right way so your help if really appreciate.


Philippe






Re: Windows Workflow Foundation Delay Activity -> long time running

Darren Headrick - MSFT

The workflow persistence service isn't really supposed to be used like that. The persistence service will allow a workflow that you have that goes idle to be removed from memory by storing it in the database, but the problem is how it gets reloaded into memory. The delay activity, like the other IEventActivitys waits for an event to occur, in this case it registers for the timeout event from the delay. You are allowing the workflow to persist into the database, and it will remain there until it times out. Now, the way we check for that timeout is to register for an event that says that the time the event was registered for has passed. Once that event occurs the delay completes and the workflow continues. If you stop the process that persisted the workflow, then there is no longer anything listening for the delays timeout, so it will just sit there in the database. The behavior you are seeing is when a timeout event occurs we rehydrate all of the workflows of the correct type that have timed out, and since your original workflow is the right type and has timed out, it gets started too.

As for your question, the best way to wakeup a workflow when the timer is reached, is to just let the original workflow wait for the event and when it is fired it will automatically get restarted. So the next question is this, why do you need to terminate the original workflow Its been persisted to memory and the resources its using are minimal, so is there a reason it needs to be terminated






Re: Windows Workflow Foundation Delay Activity -> long time running

Philippe Sillon

Hi,

Based on this link : http://msdn2.microsoft.com/en-us/library/ms734764.aspx

Many business processes take long periods of time to complete (up to many months or even years). Holding the workflow in memory is not only impractical (because of memory limitations), but it also prevents scaling because an instance must be processed on a single server. Many of these long-running workflows are not actively executing flow or process logic and are effectively idle, waiting for input from users or other systems. By unloading an idle instance, the host application can save memory and enable scalability across processing servers.


Point 1 : Web server receive 400 orders by days and each one have 2 product (averages) : so 800 products ordered by day. Right now, worklfow will be attach on only one product but imagine that 100 workflow are start by day and waiting for 10 days : it means that 1000 workflow will still running in memory I wondering what will be the impact on server Is it a best practice Smile


Point 2 : What append if server restart. I think I need to persist workflow anyway and reload it on server start


Point 3 : Can I take advantage on persistence and possibility of sql persistence service to pool database to detect timer expired

SqlWorkflowPersistenceService.LoadingInterval Property : The frequency at which the persistence service will poll the database for workflows with expired timers.
http://msdn2.microsoft.com/en-us/library/system.workflow.runtime.hosting.sqlworkflowpersistenceservice.loadinginterval.aspx

Can I create program (service ) to poll database and wake-up workflow Is it a bad idea Smile

I think it's better to have a software that poll database (each hour for example) otherwise have 1000 workflow running in memory.

All feedback will be really appreciate Wink

Thank you

Philippe.






Re: Windows Workflow Foundation Delay Activity -> long time running

NDG

Assume you would perform this task manually. Reminder documents are put on a pile and every day a person would read them and check if the time is right to send the reminder. If the time is right the document is removed from the pile, if not the document is re-entered in the pile.

You could simulate this process with the persistence service.

- After order creation the workflow is created, delayed (eg for 10 days) and persisted.

- Each night you can run a batch console application that starts the workflow runtime with the persistence service. The persistence service will automatically pick up and process the persisted workflows where the delay time has expired.

You have 2 processes:

- The order creation process to create the workflow

- The batch to process the persisted workflows.

Working in this manner, assures you that the expired workflows are at least processed on a daily base. You don't have to 'hope' that somewhere, sometime the persistence service got started. You are sure that the workflows are processed at least once a day.

From a resource-consumption point of view, you're only using server resources during the run of the batch application outside the business hours (assuming the night is a calm period for the servers). You don't need to waste resources on a service or on memory-stored workflows.






Re: Windows Workflow Foundation Delay Activity -> long time running

Darren Headrick - MSFT

I agree wuth NDG's assessment on this one, you could add another app that looks for expired workflows. And loads them, heres something to get you started:

TimeSpan instanceOwnershipDuration = TimeSpan.MaxValue;
TimeSpan loadingInterval = new TimeSpan(0, 2, 0);

SqlWorkflowPersistenceService persistence =
new SqlWorkflowPersistenceService(
"Data Source=localhost;Initial Catalog=Store;Integrated Security=True;Pooling=False",
true,
instanceOwnershipDuration,
loadingInterval );

// get all the persisted instances' description

IEnumerable<SqlPersistenceWorkflowInstanceDescription> old = persistence.GetAllWorkflows();

foreach (SqlPersistenceWorkflowInstanceDescription desc in old)
{
// if the workflow is blocked then it wont get rehydrated automatically by the runtime at startup

if (desc.IsBlocked &&

// check to see if the timer has expired
desc.NextTimerExpiration.CompareTo(DateTime.Now.ToUniversalTime()) == -1)
{

// reload the workflow
runtime.GetWorkflow(desc.WorkflowInstanceId).Load();
}
}

I would be interested however to see if there is another solution to this situation, anyone have ideas






Re: Windows Workflow Foundation Delay Activity -> long time running

Philippe Sillon

Hi,

If you check code retrieve via reflector in class System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, loading of workflow is appear to be automatic.. no

protected override void OnStarted()
{
if (this.loadingInterval > TimeSpan.Zero)
{
lock (this.timerLock)
{
base.OnStarted();
this.loadingTimer = new SmartTimer(new TimerCallback(this.LoadWorkflowsWithExpiredTimers), null, this.loadingInterval, this.loadingInterval);
}
}
this.RecoverRunningWorkflowInstances();
}

and
private void RecoverRunningWorkflowInstances()
{
if (Guid.Empty != this._serviceInstanceId)
{
using (PersistenceDBAccessor accessor2 = new PersistenceDBAccessor(this._dbResourceAllocator, this._enableRetries))
{
Guid instanceId;
while (accessor2.TryRetrieveANonblockingInstanceStateId(this._serviceInstanceId, this.OwnershipTimeout, out instanceId))
{
try
{
base.Runtime.GetWorkflow(instanceId).Load();
continue;
}
catch (Exception exception2)
{
base.RaiseServicesExceptionNotHandledEvent(exception2, instanceId);
continue;
}
}
}
}
else
{
IList<Guid> list = null;
using (PersistenceDBAccessor accessor = new PersistenceDBAccessor(this._dbResourceAllocator, this._enableRetries))
{
list = accessor.RetrieveNonblockingInstanceStateIds(this._serviceInstanceId, this.OwnershipTimeout);
}
foreach (Guid guid in list)
{
try
{
base.Runtime.GetWorkflow(guid).Load();
continue;
}
catch (Exception exception)
{
base.RaiseServicesExceptionNotHandledEvent(exception, guid);
continue;
}
}
}


}