Friday, September 14, 2007

Locked Workflow

I've periodically come across this SPException: "This task is currently locked by a running workflow and cannot be edited" when using the SPWorkflowTask.AlterTask method, even when it seems that the workflow is not in fact locked, and is instead patiently listening for an OnTaskChangedEvent. It turns out that this exception is thrown when the WorkflowVersion of the task list item is not equal to 1, which, if you believe the error message is the same thing as checking to see if the workflow is locked. Only it isn't - apparently sometimes at least, the Workflow version is non zero and the workflow is not locked (the InternalState flag of the workflow does not include the Locked flag bits). I'm not sure why this is occurring - maybe the error message is misleading - but the following code demonstrates a dodgy sort of a workaround that I've found useful. I've no idea if this is a good idea or not, so please treat with skepticism...

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using System.Collections;
using System.Threading;
 
namespace DevHoleDemo
{
    public class WorkflowTask
    {
        public static bool AlterTask(SPListItem task, Hashtable htData, bool fSynchronous, int attempts, int millisecondsTimeout)
        {
            if ((int)task[SPBuiltInFieldId.WorkflowVersion] != 1)
            {
                SPList parentList = task.ParentList.ParentWeb.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];
                SPListItem parentItem = parentList.Items.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);
                for (int i = 0; i < attempts; i++)
                {
                    SPWorkflow workflow = parentItem.Workflows[new Guid(task[SPBuiltInFieldId.WorkflowInstanceID].ToString())];
                    if (!workflow.IsLocked)
                    {
                        task[SPBuiltInFieldId.WorkflowVersion] = 1;
                        task.SystemUpdate();
                        break;
                    }
                    if (i != attempts - 1)
                        Thread.Sleep(millisecondsTimeout);
                }
            }
            return SPWorkflowTask.AlterTask(task, htData, fSynchronous);
        }
    }
}

18 comments:

Anonymous said...

Thank you so much for the tip, your code did the trick. I think the reason WorkflowVersion changes is because there's a different version of the workflow dll. So when you recompile your workflow and DLL is changed in the GAC while there are still running workflows, trying to finish any of those workflows might give you "This task is currently locked.." error.

Elena.

jj said...

Thank you very much. I had the same problem, your solution works fine.

Pete_the_Magical_Munchkin said...

How would I use this code snippet? Do you have an example of that?

txs8311 said...

You could use it as you would the SPWorkflowTask.AlterTask method, adding the attempts and timeout parameters. Here's someone who was having issues and posted some code:

http://www.serious-sam.net/serendipity/index.php?/archives/18-More-SharePoint.html

Tibor Molnar said...

Thank u very very much! With this I was able to resurrect some workflows having randmonly this issue. What I would like is to find out the reason. Why this attribute is left with values like 1024, 8096? It's cleary a flag. I think I will take a look in the WSS 3.0 assemblies to find out when is set.

Cheers,

Tibi

Anonymous said...

The solution is really great but in our scenario the DLL was same, we never changed it but were facing the issue. Thanks anyway!!!

Linda said...

I'm having this problem with my workflow! Can you please give me some directions how to use the code snippet above??

حامد باقرزاده said...

Hey Friend
I have same problem, but in my case, workflow is not firing OnTaskChanged event and workflow is locked for ever

i dont know how to resolve this problem, can you help me?

Mind said...

Hi there, I didn't really know how to implement the code you posted, but I decided to fish around and try some things out manually. I know it's highly frowned upon, but I was able to run some UPDATE queries on the AllUserData table that stored those workflows. I changed the non-1 versions to 1, and it solved my problem (for now). Here's what I did.

UPDATE dbo.AllUserData
SET tp_WorkflowVersion='1'
WHERE tp_WorkflowVersion != '1'
AND tp_DirName = 'quality/Lists/Document Review Tasks'

You would change tp_DirName to whatever directory/list/task list name you are dealing with.

If anyone can shed some light as to how to implement the code in this blog, that would be very helpful!

حامد باقرزاده said...

Hi,
I have same problem
in my case ontaskchanged not fire and workflow locked for ever.
i can solve my problem by removing onTaskCreated Activity from my workflow and now my workflow is working properly.

my previous workflow

CreatetaskWithContentType
onTaskCreated
While
onTaskChanged
End While
completeTask

my workflow now

CreatetaskWithContentType
While
onTaskChanged
End While
completeTask

حامد باقرزاده said...

hi

I solved my problem by removing onTaskCreated Activity from workflow


I have same problem, but in my case, workflow is not firing OnTaskChanged event and workflow is locked for ever

Djavan ROA said...

Hi thx so much this saved my day!

I included your method in my full example to notify a workflow from an external event (http://sharepointologic.blogspot.com/2010/11/programmatically-approve-sharepoint.html

J Carter said...

Thanks very much for your assistance on this matter. I had to dynamically set a field on the workflow task item which required a item.Update() method call. This update was then causing a lock. By setting the task workflow version back to 1 this removed the problem.

Anonymous said...

In my case I had this problem on a workflow that was an out-of-the-box MOSS workflow. I found the comment from Mind to be very helpful. Of course this is highly discouraged, but it does seem to work perfectly.

The only thing I would add is that if you hover over your stuck list item in the task list then you will see the ID of the item at the end of the link (bottom left corner). Use this ID and use 'and tp_ID = ####' instead of tp_DirName. This will help ensure that you update only one item at a time (if that's what you want). I figure this is safer than a bulk update. I also checked what would be updating first by running a similar select command first.

SELECT * FROM dbo.AllUserData
WHERE tp_WorkflowVersion != 1
AND tp_ID = ####

Ryan said...

Nothing here worked for me, until I found this: http://blogs.sharepointpro.net/2011/02/24/this-task-is-currently-locked-by-a-running-workflow-and-cannot-be-edited.aspx?results=1

Unlock all locked workflow tasks with a single PowerShell command, ridiculously easy.

Ryan said...

Nothing here worked for me, until I found this: http://blogs.sharepointpro.net/2011/02/24/this-task-is-currently-locked-by-a-running-workflow-and-cannot-be-edited.aspx?results=1

Unlock all locked workflow tasks with a single PowerShell command, ridiculously easy.

Ryan said...

Nothing here worked for me, until I found this: http://blogs.sharepointpro.net/2011/02/24/this-task-is-currently-locked-by-a-running-workflow-and-cannot-be-edited.aspx?results=1

Unlock all locked workflow tasks with a single PowerShell command, ridiculously easy.

Suvitruf said...

حامد باقرزاده,oh man...u rly helped me. I removed onTaskCreated Activity and it's work. But i can't understand why it's work now :D