Administrators need to be careful while configuring workflows and their trigger conditions in Dynamics CRM. Sometimes when we call workflows by using the wrong condition, like update of any field, and the workflow calls other child workflows then this could cause a loop. Dynamics 365 detects infinite loop but if you have many such workflows chained together then by the team Dynamics 365 detects the loop it is already too late. In Dynamics 365 online this could result in a huge problem as these workflows can consume all your storage space and they can render your system unusable.
Whenever a workflow is called, it creates a record in the system job table in the backend. And when workflows are called in a loop it creates a huge bunch of records in the system job table and consumes your whole space. One of our clients faced a very similar issue.
We have followed following steps to clear space consumed by system job.
1)
First, we deactivated the workflows which were being called due to wrong business logic.
2)
“Waiting For Resources” system job records can’t be deleted as it is. First, we need to cancel these system jobs.
So, we have written a utility to achieve this. First, we will fetch those system job records which are “Waiting For Resources” and then update their status to “Cancelled”.
In the following code we have cancelled all “System Jobs” records which are “Waiting For Resources”.
public void UpdateInBulk (IOrganizationService _orgService) { Int32 pageNumber = 1; // Initialize the number of records. int fetchCount = 1000; // Specify the current paging cookie. For retrieving the first page, // pagingCookie should be null. string pagingCookie = null; string fetchXml = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'> <entity name='asyncoperation'> <attribute name='asyncoperationid' /> <attribute name='name' /> <attribute name='regardingobjectid' /> <attribute name='operationtype' /> <attribute name='statuscode' /> <attribute name='ownerid' /> <attribute name='startedon' /> <attribute name='statecode' /> <order attribute='startedon' descending='true' /> <filter type='and'> <condition attribute='operationtype' operator='eq' value='10' /> <condition attribute='statuscode' operator='eq' value='0' /> </filter> </entity> </fetch>"; while (true) { // Build fetchXml string with the placeholders. string xml = CreateXml (fetchXml, pagingCookie, pageNumber, fetchCount); // Excute the fetch query and get the xml result. RetrieveMultipleRequest fetchRequest1 = new RetrieveMultipleRequest { Query = new FetchExpression(xml) }; EntityCollection returnCollection = ((RetrieveMultipleResponse)_orgService.Execute(fetchRequest1)). EntityCollection; List<Entity> updateCollection = new List<Entity>(); foreach (var c in returnCollection.Entities) { var updateEntity = new Entity("asyncoperation"); updateEntity.Id = c.Id; updateEntity["statecode"] = new OptionSetValue(3); // 3 is for status cancelled try { updateCollection.Add(updateEntity); } catch (Exception ex) { } } BulkUpdateSystemJobRecords (_orgService, updateCollection); // Check for morerecords, if it returns 1. if (returnCollection.MoreRecords) { Console.WriteLine("\n****************\nPage number {0}\n****************", pageNumber); // Increment the page number to retrieve the next page. pageNumber++; // Set the paging cookie to the paging cookie returned from current results. pagingCookie = returnCollection.PagingCookie; } else { // If no more records in the result nodes, exit the loop. break; } } } public static void BulkUpdateSystemJobRecords(IOrganizationService service, List<Entity> entities) { // Create an ExecuteMultipleRequest object. var multipleRequest = new ExecuteMultipleRequest() { // Assign settings that define execution behavior: continue on error, return responses. Settings = new ExecuteMultipleSettings() { ContinueOnError = false, ReturnResponses = true }, // Create an empty organization request collection. Requests = new OrganizationRequestCollection() }; // Add a UpdateRequest for each entity to the request collection. // Execute all the requests in the request collection using a single web method call. } if (null == childNode) public string ExtractAttribute(XmlDocument doc, string name) public string CreateXml(string xml, string cookie, int page, int count) // Load document return CreateXml(doc, cookie, page, count); public string CreateXml(XmlDocument doc, string cookie, int page, int count) if (cookie != null) XmlAttribute pageAttr = doc.CreateAttribute("page"); XmlAttribute countAttr = doc.CreateAttribute("count"); StringBuilder sb = new StringBuilder(1024); XmlTextWriter writer = new XmlTextWriter(stringWriter); return sb.ToString(); |
3)
Now we can run bulk deletion job. Go to “System Jobs” from Settings. Go to More Actions and click on Bulk Delete.
4)
When “Bulk Delete” job is run successfully space is available automatically. However, we will have to wait for a few hours till “Total Storage Used” status is updated in your Dynamics 365. You can check the status in “Service Health” section of your Dynamics CRM.
That’s it for today. Hope this will be helpful next time you face such scenarios. Thanks!!!
If you have any question or queries, do not hesitate to reach out to us!