I recently joined a project which automates different processes from a company using MOSS 2007 with Workflow Foundation and InfoiPath 2007 forms.
We have the following scenario: create a SharePoint task in a deployed workflow with the CreateTask activity, wait for its completion with the OnTaskChanged activity and then delete the task with the DeleteTask activity. We have to control the timeout, so we tried to use in a parallel branch a Delay activity.
In SharePoint 2007, if a workflow has a delay activity in a repeating control, the workflow goes idle and is persisted as designed but it is not awaked always as expected. We run several tests by puttting a one minute delay in an infinite While loop, sometime is working even for few hours but after that the workflow is awaked randomly (might happen that more that 1 hour passes, instead of the set 1 minute, before anything happens).
Beign a Gold Certified partner, we opened an incident at Microsoft, we found out that this is a known issue but right now it is not planned to be solved.
The workaround:
- create a console application (the timer service) which iterates through a SharePoint web site's list to which the worklow is attached and for every item, for the attached tasks, calls the SPWorkflowTask.AlterTask method just to trigger an update on the task
- register this console application in the Windows Scheduling service
- do not use a Delay activity in a parallel branch, put the OnTaskChanged in a While loop
- any time the scheduled console app updates the corresponding task, check in the Invoked event handler of OnTaskChanged whether the task was completed or we have a timeout, if non of these happens, loop again, wait for the next update which can come from the scheduled app or the user to whom the task is assigned
The code below is the part of the timer service that iterates all subsites of a site and updates a any SPWorkflowTask attached to any item from a list with a given name. The code references the Microsoft.Office.Servers and Microsoft.SharePoint assemblies. You can change it easily upon your needs.
using (SPSite site = new SPSite("your site url"))
{
ServerContext context =
ServerContext.GetContext(site);
SPWebCollection allSites = site.AllWebs;
SPWorkflowManager SPWFM = site.WorkflowManager;
foreach (SPWeb subSite in allSites)
{
SPListCollection allSiteLists = subSite.Lists;
foreach (SPList subSiteList in allSiteLists)
{
if (subSiteList.Title == "your list name")
{
SPQuery query = new SPQuery();
query.Query = "";
SPListItemCollection listItems = subSiteList.GetItems(query);
foreach (SPListItem listItem in listItems)
{
// active workflows
SPWorkflowCollection SPWFCollection = SPWFM.GetItemActiveWorkflows(listItem);
foreach (SPWorkflow SPWorkflow in SPWFCollection)
{
foreach (SPWorkflowTask SPWFTask in SPWorkflow.Tasks)
{
Hashtable SPTaskExtendedProperties = SPWorkflowTask.GetExtendedPropertiesAsHashtable((SPListItem)SPWFTask);
logger.Info(string.Format("Updating task with title {0}.", SPWFTask.Title));
try
{
SPWorkflowTask.AlterTask((SPListItem)SPWFTask, SPTaskExtendedProperties, true);
}
catch (Exception exc)
{
logger.Error("Error altering task: ", exc);
}
}
}
}
}
}
}
}