João Ricardo Pereira

Hi,

I'm using a state machine workflow that steps through several states in a ASP.NET application.
I use Custom Tracking to track user data and the out of the box PersistenceService.

For each state I have a control that displays in a gridview the list of workflows that are waiting for that step. When the user selects the instance, it redirects to another control that asks for some information in order to submit and call the event referenced by the HandleExternalActivity in the WF.

The problem is that there are more than one person processing each step, so I need to lock each instance to the user when they begin the attendance.

I've done some research and found that the Persistence Service provides a "Locking Workflow State Information" method that I found very interesting.

I'll try to explain myself what I'm trying to do...

I create the attendance list through TrackingServices, executing a SqlTrackingQueryOptions filtered by WF Type and by CompanyID so that it returns a small IList<SqlTrackingWorkflowInstance>. Then I check if the last record is waiting for the state I am listing and add it to the list.

What I'm trying to do is query the persistence DB checking if each one of the instances I add to the list is locked, and if so, do not add it.

I'm trying to do something with SqlPersistenceWorkflowInstanceDescription but first of all I only manage to get all the workflows in the persistence service, which is a little unacceptable because there could be several hundreds or millions of persisted instances.
List<SqlPersistenceWorkflowInstanceDescription> s = persistenceService.GetAllWorkflows() as List<SqlPersistenceWorkflowInstanceDescription>;

Even so, there is a method Find(), that I can't figured it out...
SqlPersistenceWorkflowInstanceDescription tree = s.Find(Predicate<SqlPersistenceWorkflowInstanceDescription> match);

Other approach I looked at was using a ListenActivity with a timeout that resolved my situation also... But I'm using StateMachine Workflow's and the activity does not exists...
I read that "EventHandlingScope" activity can do the trick, but it seems a little odd to process things like that...

What's the best approach do you guys recommend me and can you give me some examples or point the way in to it



Re: Windows Workflow Foundation SqlPersistenceWorkflowInstanceDescription Help!

Clement Leung - MSFT

There seems to be no easy solution to this problem, but try doing this:

You can build a list of appropriate workflows instances using Tracking Service data. As you said, this list is small compared to the total number of persisted instances. You can show these instances to all the users. Once users select a workflow instance, call workflowRuntime.GetWorkflow(guid).Load() on behalf of that user . If that particular instance is locked, Load() will throw an exception, and you can throw an error back to the user stating that the workflow is locked. Then you can update the workflow list to exclude that instance.The downside of this approach is that the users might get multiple ownership exceptions.

If you are willing to write custom code, here is what you can do:

Create your own database table called 'LockedInstances' which contains InstanceId column (and may be other columns). Build the appropriate in-memory instance list using tracking data. For each instance in the list, check 'LockedInstances' table and see if there is an entry for that instance. If you don't find an entry, then it means that nobody has Loaded and locked the workflow instance. That means you can show this instance to the user. Once user selects an instance, you check the 'LockedInstances' table again and if it still does not contain an entry, add an entry for that instance and Load() workflow instance. Now, you need a mechanism to remove the entry from 'LockedInstances' table. You can subscribe to WorkflowRuntime's WorkflowUnloaded event. When this event is fired, remove the entry from the table. You might have other ways to detect when an instance is unloaded.






Re: Windows Workflow Foundation SqlPersistenceWorkflowInstanceDescription Help!

Joao Ricardo Pereira

Thanks for your answer.

The downside of the first approach you mentioned is that it's really NOT user friendly. The ideal was to list only the instances that aren't locked...

The second approach you mentioned already occurred to me, but it's a little "forgetting" the WF and go on "manual"...

I also thought in creating a Stored Procedure that receives the InstanceID and returns 0 or 1 if the instance is locked or not (not forgetting the OwnedUntil field of the table). This way I think I can populate the DataGrid with unlocked instances and I can verify, on user selection, if the instance remains unlocked.
I'd like to ear your opinion about this approach, but I think it's user friendly, performance still remains and I still take the most advantage out of the Workflow Out-of-Box Services.

Other concern I thought in was regarding the thread pool...
When the user selects the instance I'll load it in memory and start it and set OwnershipTimeoutSeconds="600". The attendance should take no longer than 10 minutes. Since I have UnloadOnIdle="false", the instance after loading remains idle for 10min or until the user submit the form.
Regarding how the thread management works, I don't know much...

Will this be a problem if the server gets overloaded

Thanks again for your support.





Re: Windows Workflow Foundation SqlPersistenceWorkflowInstanceDescription Help!

Tom Lake - MSFT

Joao Ricardo Pereira wrote:

For each state I have a control that displays in a gridview the list of workflows that are waiting for that step. When the user selects the instance, it redirects to another control that asks for some information in order to submit and call the event referenced by the HandleExternalActivity in the WF.

The problem is that there are more than one person processing each step, so I need to lock each instance to the user when they begin the attendance.

I've done some research and found that the Persistence Service provides a "Locking Workflow State Information" method that I found very interesting.

The workflow will not be locked until after the event that the handle external event activity subscribes to is raised, not when the user selects the instance. It will only stay locked until the workflow becomes idle and is persisted again, which is normally a fairly short period of time.

It might be simpler to just handle either the WorkflowOwnershipException or an EventDeliveryException and give the user a message like ¡°Instance already being process for step ¡®foo¡¯¡±.

Joao Ricardo Pereira wrote:

Even so, there is a method Find(), that I can't figured it out...
SqlPersistenceWorkflowInstanceDescription tree = s.Find(Predicate<SqlPersistenceWorkflowInstanceDescription> match);

Predicate is a generic delegate used to compare items in a List<T> to find a particular item, for more information see http://msdn2.microsoft.com/en-us/library/bfcke1bz(vs.80).aspx. Below is an example of how to use the Find method with the list returned from GetWorkflows, orderId is the instance id that is being looked for:

List<SqlTrackingWorkflowInstance> queriedWorkflows = (List<SqlTrackingWorkflowInstance>)sqlTrackingQuery.GetWorkflows(new SqlTrackingQueryOptions());

SqlTrackingWorkflowInstance sqlTrackingWorkflowInstance = queriedWorkflows.Find(delegate(SqlTrackingWorkflowInstance workflowInstance)

{

return workflowInstance.WorkflowInstanceId == new Guid(orderId);

});






Re: Windows Workflow Foundation SqlPersistenceWorkflowInstanceDescription Help!

Joao Ricardo Pereira

Thank you for answering.

I've set UnloadOnIdle to false and used the persistence locking system to do the trick.

When the user selects an item from the list, I resume the workflowInstance that locks the instance and place the WorkflowRuntime in Session so that only that user can access it...

To display only the unlocked items I've created a simple stored procedure in the TrackAndPersist DB, that tells me if the instance is locked or unlocked, but I think that I will review this and use the Find() method like you described in the above example.

The only problem with this is that persistence becomes a little manual, but like we structured the project, it's fair simple to manage this...
It can have other problems, like if the user closes the browser, the instance will be locked until the lock expires, but in this case I think there won't be any problem...

Thank you very much for your time.

Best regards





Re: Windows Workflow Foundation SqlPersistenceWorkflowInstanceDescription Help!

HANK1

Hi Joao Ricardo Pereira

Sorry for bother you with this question but I want to hear for your experience how the users work with WFs. Did you develop an interface where the users start and work with the workflows (ASP.net) How do users know that they need to do something in the workflow do you send e-mails notification or add a task in outlook or...

Regards

Henry





Re: Windows Workflow Foundation SqlPersistenceWorkflowInstanceDescription Help!

Joao Ricardo Pereira

Hi,
No bother at all...

Actually, users don't know that the interface they're working on is built on Windows Workflows...
We use workflows to control the flow of information within the application. For the end user, this is just like a normal asp.net application, but for us, it become easier to develop and more intuitive to control which steps are available next and what needs to be done...
We developed two levels of workflows, the first (mostly sequential workflows) for simple tasks, and the second (all state machine) to control each life cycle of the client.

Windows workflow also have the tracking and persistence engines that we use. It becomes easier to just persist the workflow and keep all the info related to it and later only resume it instead of save all the info we need on various records in the DB... The tracking it's also extraordinary, not only to query which workflows are on a specif state or to get all the info from a specific instance, but also to keep a background history of all that happens on the system.

About this:
"How do users know that they need to do something in the workflow "

We're implementing an Alert Module that's responsible for deliver tasks to the users. When a workflow is waiting for a task from a user or from a group of users, we create an alert in the application, telling that some work needs to be done, that is delivered when the user or someone from the group is logged in. The user then can click the alert, and be redirected to the task he needs to complete.

I hope I answered your question...

Best regards
Joao Pereira