Follow Up - Programmatically approving a workflow


In my previous post “SharePoint 2010: Programmatically Approving/Rejecting Workflow” I mentioned the possibility of an issue when programmatically altering a workflow task. I have been testing it on several SharePoint 2010 farms with different parameters (different patch level, etc).

UPDATED July 2, 2011: RESOLVED

Set up

A simple SharePoint Designer 2010 workflow with the “Start Approval Process” action published to a document library. You start the workflow and a task is created for the approver.

The Approver is set to another test user, but all my code and script runs as the administrator (and thus System Account). Makes no difference though.

Note: when running the workflow multiple times (for testing), make sure to delete all tasks that are linked to your item. Or adapt the code below to not just take the first task in the collection…

Issue experienced

You alter the workflow task using a Visual Studio Console Application or Windows Application with the following (or similar code):

1 string url = "http://intranet/Shared Documents/Instructions.txt"; 2 using (SPSite site = new SPSite(url)) 3 { 4 SPWeb web = site.RootWeb; 5 SPListItem item = web.GetFile(url).Item; 6 SPWorkflowTask task = item.Tasks[0]; 7 8 Hashtable ht = new Hashtable(); 9 ht["TaskStatus"] = "Approved"; 10 11 SPWorkflowTask.AlterTask(task, ht, false); 12 }

After the code has run successfully you don’t see anything happen in the workflow status page. On some occasions you get “Due to heavy load, the latest workflow operation has been queued. It will attempt to resume at a later time” which could mean that the timer job hasn’t completed successfully yet. This message may or may not disappear for you.

Also, when trying to do a second alteration to the workflow task (by code or in the UI) you get “This task is currently locked by a running workflow and cannot be edited”.

So somehow your action was registered but not executed…

PowerShell to the rescue

Terminate the workflow (because it really hangs and there’s not much you can do with it) and kick off a new one.

Now open the SharePoint 2010 Management Shell (PowerShell) and run the following (or similar code):

$s = Get-SPSite("http://intranet")
$w = $s.RootWeb
$i = $w.GetFile("
http://intranet/Shared Documents/Instructions.txt").Item
$t = $i.Tasks[0]
$ht = new-object Hashtable
$ht["TaskStatus"] = "Approved"
[Microsoft.SharePoint.Workflow.SPWorkflowTask]::AlterTask($t, $ht, $false)

This WILL work and correctly finish the approval cycle in any of my tested environments.

Notes

You can really test this over and over and over; it will work in PowerShell but not in the Visual Studio 2010 application. I have tested Release versus Debug, in and out Visual Studio, etc.

Solution (July 2, 2011)

The big difference in both techniques is that the PowerShell remains open and isn’t disposing any objects. This allowed the workflow engine to complete the task.

Option #1
1 SPWorkflowTask.AlterTask(task, ht, true);

From MSDN:

“If true is passed as the argument to fSynchronous, this method waits up to 30 seconds to determine whether the attempted update was accepted by the workflow schedule as valid. The method then returns true if the update was accepted and not rolled back, or false if the update was not accepted. If false is passed as the argument to fSynchronous, this method always returns true.”

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.workflow.spworkflowtask.altertask.aspx

 

I have found this working most of the times, however some test runs still experienced the issue. Perhaps my test environment isn’t powerful enough or the action takes just a little too long to kick in ?

Option #2

Using the code below I learned it took about 21 seconds for the task to complete:

1 int i = 1; 2 while (!(bool)item.Tasks[taskId]["Completed"]) 3 { 4 Console.Clear(); 5 Console.Write("" + i + " " + task["Completed"]); 6 Thread.Sleep(1000); 7 i++; 8 }

That should give ‘option #1’ suffice time to complete the task, but still it didn’t in all occasions. If you’re experiencing this you could write up your own delay either as replacement to, or in combination with ‘option #1’.

1 SPWorkflowTask.AlterTask(task, ht, true); 2 // Additional delay 3 while (!(bool)item.Tasks[taskId]["Completed"]) 4 { 5 Thread.Sleep(1000); 6 }
Related

 

Big kudos to my colleagues Tom De Wilde and Timmy Gilissen for helping me out !!

 


Links to this post

Comments

Wednesday, 31 Aug 2011 12:57 by SimonO
Sounds like you hit similiar problems to me and most likely other sharepoint users. I created a workflow for a pages library that had the same approval task that you used, but it had an impersonate step before the approval task to replace permissions. I found that it doesnt allows start on item create, sometimes it may start but the task doesnt get created so no way to prgress with the workflow, other times it works fine. I then thought I could just kick it off using the manual start, but again inconsistant behaviour as above. Was able to repeat this on multple server environments. It maybe even more unstable since i am replacing perms?? I wonder if custom workflows are just not designed for pages library, not that ive seen any documentation to support this.

Friday, 13 Apr 2012 04:42 by Christian
Hi Steven, thanks for this blogposts, i guess it might me very helpful (if i could get the solution working!!!). In my unterstanding it is possible to complete a workflow task by executing this poershell code: ($s = Get-SPSite("http://intranet") $w = $s.RootWeb $i = $w.GetFile("http://intranet/Shared Documents/Instructions.txt").Item $t = $i.Tasks[0] $ht = new-object Hashtable $ht["TaskStatus"] = "Approved" [Microsoft.SharePoint.Workflow.SPWorkflowTask]::AlterTask($t, $ht, $false) I can't get this code working in my environment, the problem seems to be the "$i = $w.GetFile("http://intranet/Shared Documents/Instructions.txt").Item " part (the following line "$t = $i.Tasks[0] " throws an exception "Cannot index into a null array"). When i use this code instead (which should pretty much do the same) $web = Get-SPWeb http://sp2010eval2/workflows $list = $web.Lists["test"] $i = $list.GetItemByID(1) $t = $i.Tasks[0] $ht = new-object Hashtable $ht["TaskStatus"] = "Approved" [Microsoft.SharePoint.Workflow.SPWorkflowTask]::AlterTask($t, $ht, $false) the task status is not changed. Only the red "Due to heavy load, the latest workflow operation has been queued. It will attempt to resume at a later time" appears. The Task is not completed. Do you have an idea why this is not working? It would be very helpful to be able to complete a workflow task using powershell. Thanks Christian

Monday, 16 Apr 2012 12:23 by Steven Van de Craen
Hi Christian, do you close the PowerShell command window immediately or does it have the time to finish the process (see the issue I'm describing) ? Make sure the file and item you are referring to exist and try outputting the tasks that are present. Make sure there is a workflow (and task) for that item that you're referencing. Also make sure the timer service is running on your box.

Wednesday, 18 Apr 2012 02:35 by Christian
Hi Steven, thanks for your reply. I have checked your suggestions an everything seems to be fine (item and workflow task are existing, timer job is running, the powershell windows stays open). When i execute the code there ist the red "Due to heavy load, the latest workflow operation has been queued. It will attempt to resume at a later time" message which dissapears a few seconds later. But the task status stays unchanged. Could this be an issue with the german language pack? Christian

Friday, 20 Apr 2012 02:58 by Steven Van de Craen
Hi Christian, could be. approve a task from the UI and query it using SharePoint manager to see the internal value of the TaskStatus. It might be the german wording for "Approved".

Sunday, 9 Jun 2013 01:12 by Wael
How i can thank you about that great article ! now i understood well what happen when the i use the parameter fsyncrhonouns ooohhhh it takes from me 3 days before i visit your blog thanks again

Wednesday, 13 May 2015 12:51 by Kalpesh Vaghela
Thanks and very helpful to me. I have tried to complete task using console application whole day and I found your blog end of the day :(

Wednesday, 17 Aug 2016 07:39 by Deepthi
Hi, I also experiencing same issue. I'm using powershell and tried with $true as well as $false, both cases same error message "Due to heavy load, the latest workflow operation has been queued. It will attempt to resume at a later time" and it takes 20+ mins to complete the task. Noticed that task status getting changed to Approved but outcome shows as empty during this delay time. [Microsoft.SharePoint.Workflow.SPWorkflowTask]::AlterTask($task, $ht, $false) Appreciate your help on this

CAPTCHA Image Validation