How to deal with Old workflow instances that are in
waiting state with old Logic?
We can accept that we are blessed with the Wait Condition
in Dynamic CRM. It could be used in many simple to complex tasks such as to send
a friendly reminders/email after certain duration.
There could be many workflow sessions running in a
waiting state considering a typical Live (Production) environment.
Re-Defining Workflow
Now imagine for some reason your business logic got
changed and you need to redefine the logic in a workflow.
Newly added logic for a respective workflow will not be
applicable for workflows instances which are already in a waiting or running
state and your business may complaint that notifications to customer are still
going on even though you have already roll-out new changes to the workflow.
Solution
To overcome such a problem, I did follow below steps.
Step 1) Get workflow
sessions which are still going ON (WAITING STATE) with OLD LOGIC
Step 2) Cancel Old workflow
session with OLD LOGIC
Step 3) Trigger New
Workflow Session for those records whose process got cancelled.
.Net Code for above outline steps
public class SwitchToNewWorkflowProcess
{
IOrganizationService _orgService;
const string regardingEntityType = "invoice";
Guid workflowId = new
Guid("1E99FA9F-3708-4107-A110-38191CC2BE59"); // (Email) License
has Expired
public SwitchToNewWorkflowProcess(IOrganizationService _orgService)
{
this._orgService = _orgService;
}
public void executionPlan()
{
// Step 1) Get
workflow sessions which are still going ON (WAITING STATE) with OLD LOGIC
EntityCollection oldWorkflowsCollection =
getOldWorkflows();
foreach (Entity sessions in
oldWorkflowsCollection.Entities)
{
if (sessions.Contains("regardingobjectid"))
{
Guid invoiceId = ((EntityReference)sessions["regardingobjectid"]).Id;
//Step 2) Cancel workflow with OLD LOGIC
cancelOldWorkflow(sessions.Id);
// Step 3) Trigger New Workflow Session for those records
whose process got cancelled.
instantiateNewWorkflow(invoiceId);
}
else
Console.WriteLine("Process Session where Regarding is not Set : " + sessions.Id.ToString());
}
Console.WriteLine("End of Execution
Plan");
}
// You need to change condition clauses
in below fetch XML to get specific workflow sessions
private EntityCollection
getOldWorkflows()
{
string fetchXmlOldSystemJob =
EntityCollection oldWorkflowsCollection =
_orgService.RetrieveMultiple(new FetchExpression(fetchXmlOldSystemJob));
return oldWorkflowsCollection;
}
private void cancelOldWorkflow(Guid workflowInstanceId)
{
Entity operation = new Entity("asyncoperation")
{
Id = workflowInstanceId //
};
operation["statecode"] = new OptionSetValue(3);
operation["statuscode"] = new OptionSetValue(32);
_orgService.Update(operation);
}
private void instantiateNewWorkflow(Guid entityId)
{
var executeWorkflowRequest = new ExecuteWorkflowRequest()
{
WorkflowId = workflowId, // Guid of workflow
EntityId = entityId // Guid of record
};
var executeWorkflowResponse = (ExecuteWorkflowResponse)_orgService.Execute(executeWorkflowRequest);
}
}
From you main method just invoke the
executionPlan() method.
IOrganizationService _orgService;
_orgService = getOrgService();
SwitchToNewWorkflowProcess obj = new SwitchToNewWorkflowProcess(_orgService);
obj.executionPlan();