Monday 21 October 2013

SharePoint 2010 Workflow Exception: "This task is currently locked by a running workflow and cannot be edited"

If you are experiencing this problem, first thing you need to check is this great post.


If your workflow is not in Visual Studio, rather it's a SPD workflow, what you can do is create a Timer Job which runs every couple of minutes and set the workflow version. Here is the Code:

 // Feature receiver  
 using System;  
 using System.Runtime.InteropServices;  
 using System.Security.Permissions;  
 using Microsoft.SharePoint;  
 using Microsoft.SharePoint.Security;  
 using Microsoft.SharePoint.Administration;  
 using **.Code.TimerJobs;  
 namespace **.Features.Unlock_Workflow_Tasks  
 {  
 [Guid("***")]  
 public class Unlock_Workflow_Tasks : SPFeatureReceiver  
 {  
 public override void FeatureActivated(SPFeatureReceiverProperties properties)  
 {  
 SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;  
 if (webApp == null)  
 return;  
 try  
 {  
 // make sure the job isn't already registered  
 foreach (SPJobDefinition job in webApp.JobDefinitions)  
 {  
 if (job.Name == JOB_NAME)  
 job.Delete();  
 }  
 }  
 catch  
 {  
 }  
 // install the job  
 UnlockWorkflowTasks timerJobDefinition = new UnlockWorkflowTasks(JOB_NAME, webApp);  
 SPMinuteSchedule schedule = new SPMinuteSchedule();  
 schedule.Interval = 15;  
 schedule.BeginSecond = 0;  
 schedule.EndSecond = 59;  
 timerJobDefinition .Schedule = schedule;  
 timerJobDefinition .Update();  
 }  
 // Uncomment the method below to handle the event raised before a feature is deactivated.  
 public override void FeatureDeactivating(SPFeatureReceiverProperties properties)  
 {  
 SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;  
 // delete the job  
 try  
 {  
 foreach (SPJobDefinition job in webApp.JobDefinitions)  
 {  
 if (job.Name == JOB_NAME)  
 job.Delete();  
 }  
 }  
 catch  
 {  
 }  
 }  
 }  
 }  
 // The Timer Job  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using Microsoft.SharePoint.Administration;  
 using Microsoft.SharePoint;  
 using **.Code.Utilities;  
 using Microsoft.SharePoint.Workflow;  
 namespace **.Code.TimerJobs  
 {  
 class UnlockWorkflowTasks : SPJobDefinition  
 {  
 public UnlockWorkflowTasks(): base() {}  
 public UnlockWorkflowTasks(string jobName, SPWebApplication webApplication)  
 : base(jobName, webApplication, null, SPJobLockType.Job)  
 {  
 this.Title = "**";  
 }  
 public override void Execute(Guid contentDbId)  
 {  
 try  
 {  
 SPSecurity.RunWithElevatedPrivileges(delegate()  
 {  
 using (SPSite site = new SPSite(WebApplication.Sites[0].Url))  
 using (SPWeb web = site.OpenWeb())  
 {  
 UnlockPotentiallyLockedWorkflowTasks(web);  
 }  
 });  
 }  
 catch (Exception ex)  
 {  
 Logger.LogError(ex);  
 }  
 }  
 private void UnlockPotentiallyLockedWorkflowTasks(SPWeb web)  
 {  
 try  
 {  
 web.AllowUnsafeUpdates = true;  
 SPListItemCollection tasks = GetPotentiallyLockedTasks(web);  
 foreach (SPListItem task in tasks)  
 {  
 try  
 {  
 if ((int)task[SPBuiltInFieldId.WorkflowVersion] != 1)  
 {  
 // change it's version to 1.0  
 SPList parentList = task.ParentList.ParentWeb.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];  
 SPListItem parentItem = parentList.Items.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);  
 SPWorkflow workflow = parentItem.Workflows[new Guid(task[SPBuiltInFieldId.WorkflowInstanceID].ToString())];  
 if (!workflow.IsLocked)  
 {  
 task[SPBuiltInFieldId.WorkflowVersion] = 1;  
 task.SystemUpdate();  
 Logger.LogInfo("Unlock task {0} (ID:{1})", task["Title"].ToString(), task["ID"].ToString());  
 }  
 }  
 }  
 catch (Exception e)  
 {  
 Logger.LogError(e);  
 }  
 }  
 }  
 catch (Exception e)  
 {  
 Logger.LogError(e);  
 }  
 finally  
 {  
 web.AllowUnsafeUpdates = false;  
 }  
 }  
 private SPListItemCollection GetPotentiallyLockedTasks(SPWeb web)  
 {  
 var query = new SPQuery();  
 query.Query = @"  
 <Where>  
 <Neq>  
 <FieldRef Name='Status' />  
 <Value Type='Choice'>Completed</Value>  
 </Neq>  
 </Where>";  
 //query.ViewAttributes = "Scope=\"Recursive\"";  
 return web.Lists[WORKFLOW_TASKS_LIST].GetItems(query);  
 }  
 }  
 }