Pages

Thursday, February 28, 2013

High Availability Workflows

Since joining Avtex, I have been able to expand my horizons and gain exposure to customers with unique needs.  I try, as hard as possible, to incorporate or build on top of CRM’s out-of-box experience, and refrain from writing code I don’t have to.  To that end, I’d like to share a simple solution to making Workflows trigger while they’re deactivated for updating.

It’s no secret that business processes change on-the-fly.  Implementing changes to active Workflows can be tricky, from an availability standpoint.  Most companies adopt a routine of modifying Workflow designs afterhours, or with operations momentarily held until the modification is complete.  This presents a dynamic and potentially troubling hurdle for “always on” companies.

Because Workflows are listeners to CRM operations, rather than direct participants, any downtime with a particular Workflow means that it’s no longer listening to events.  This allows for the potential of unapplied business logic, and can be very difficult to diagnose or troubleshoot.

Though the space of downtime can be reduced to mere minutes—by developing in an alternate environment and shipping the updated Workflow in as a Solution—the window of opportunity for actions to tip-toe past a disabled Workflow still exists.  For some companies, this is simply unacceptable.

However, you can use the out-of-box Workflow abilities to create high availability Workflows that can be taken offline, modified, and then reactivated, all without missing a single event that was triggered while the Workflow was offline.  This works by splitting the Workflow’s functionality into two separate Worfklows:

  1. An event listening “Dispatcher” Workflow; and
  2. A “Business Logic” application Workflow

By isolating the business logic into a “child Workflow” which is called by its corresponding Dispatcher, one can take the Business Logic offline, while leaving the Dispatcher functional.  This allows the configured triggers of the Dispatcher to operate continuously, though the step which calls the Business Logic counterpart will fail during the downtime.

Though the Dispatcher jobs enter a “Waiting” state, they will be easy to identify (especially if you allow them to delete themselves when they’re successful) in order to resume.  This behavior is generally sufficient enough to allow a wider window for Business Logic adjustment, without requiring additional intervention to process the new logic against records that are awaiting to execute the new logic.  That brings up another excellent advantage to this pattern:

With Dispatchers, you can immediately terminate existing logic and immediately register all further processing against future logic.

Note:  You cannot retarget a different workflow, as that would require taking the Dispatcher offline—which defeats the purpose.  The System Job acts as a cloned instance of a Workflow, so the Dispatcher will always target a specific, business-logic Workflow.  You can approximate a retargeting scenario with Dispatcher juggling, but it would involve trigger overlapping mitigation.

Here’s an example scenario that uses a Dispatcher to update an Account using the Dispatcher and Business Logic pattern:

First, create the Business Logic workflow, and for “Available to Run” select “As a child process”.  Remove all selections from “Options for Automatic Processes”.

image

Then, create the Dispatcher workflow with the “Options for Automatic Processes” setting you desire, and configure it to call your Business Logic workflow.

image

You may now activate both.  Your Dispatcher is diligently watching the events, and the Business Logic is processing your rules.

Here is what happens when you deactivate the Business Logic workflow to make modifications:

image

My example uses a Dispatcher that listens to Account creation, so when I create a new account, here is what I see in the “Workflows” associated to it:

image

As you can see, the Dispatcher caught the event, and then entered a “Waiting” state.  If we examine the job, we can see the error:

image

It failed on the step that calls my Business Logic.  This job will remain in this state until I resume it.  After completing my modifications to Business Logic, I’ll reactivate it.  Then, I need to identify all my outstanding Dispatcher jobs:

image

Then, resume them with the confidence that I have missed no important triggers while my Business Logic was momentarily offline:

image

That said, I always perform a quick validation, just to be sure:

image

Monday, February 11, 2013

A Potent Cocktail: ExecuteMultiple and LINQ

I love it when technologies using the same framework marry together like peaches and cream.  Today, I want to cover the intersection of CRM 2011’s new ExecuteMultiple capabilities and my love of LINQ.  Just to be clear, I’m not talking about using LINQ provider for CRM, though you can certainly use that to produce a collection of records upon which to perform some operation in bulk.

Instead, I’d like to show you an elegant snippet of code that demonstrates the power of ExecuteMultiple with the cleanliness of succinct LINQ.  Given an EntityCollection —someRecords— suppose that you need to increment some integer —my_integer— on each of the contained records.  For the purposes of this example, I’ll be using the late-bound Entity type.

// Start our request with some basic initialization
ExecuteMultipleRequest bulkIncrementRequest = new ExecuteMultipleRequest()
{
    Settings = new ExecuteMultipleSettings()
    {
        ContinueOnError = true,
        ReturnResponses = true
    },
    Requests = new OrganizationRequestCollection()
}

// Compile the collection of requests
bulkIncrementRequest.Requests.AddRange( from record in someRecords.Entities
                                        where record.Contains( "my_integer" )
                                        select new UpdateRequest() 
                                        { 
                                            Entity = new Entity( "someRecord" )
                                            {
                                                Id = record.Id,
                                                Attributes = {
                                                    new KeyValuePair( "my_integer",
                                                        ( ( Int32 ) record[ "my_integer" ] ) + 1 )
                                                }
                                            }
                                        } );

// Excute the requests
ExecuteMultipleResponse bulkIncrementResponse = ( ExecuteMultipleResponse ) service.Execute( bulkIncrementRequest );

// Check "IsFaulted" to determine if any of the submitted requests failed
if ( bulkIncrementResponse.IsFaulted )
{
    Int32 errorCount = ( from incrementResponse in bulkIncrementResponse.Responses
                         where incrementResponse.Fault != null
                         select incrementResponse ).Count();
}

By using LINQ to inject the AddRange method of Requests, I was able to compound the code that loops through each record, selects the original value, increments it, and produces a request to update the record. 

Keen observers notice that I created a new Entity object from the old one; this is a best-practice to avoid triggering updates on attributes undesirably.  However, it also allows me to perform the increment operation inline.  I’m sure you could inject this operation into a secondary where statement, but I think that makes the query logic less readable.  But your mileage may vary.  :)

Wednesday, February 6, 2013

Add Parameters to CRM 2011 Lookup Dialog

Alternate Title: How to hide the “New” or “Properties” button from the CRM 2011 Lookup Dialog.

Following on the heels of yesterday’s post, I have finally discovered a way to eliminate the pesky “New” and “Properties” buttons from the Lookup dialog.  This was, again, easier accomplished in the previous version of CRM, with the following code:

   1:  crmForm.all.<lookup>.AddParam("ShowNewButton", 0);

As we’ve seen before, this function did not disappear from CRM 2011—it was simply moved.  Now, this function is invoked somewhat implicitly via a behavioral association to a highly organized JavaScript object structure.  Yet again, hours of pouring over Developer Tools in Internet Explorer (this time with a lot more Profiling and debugging), I have figured out how Microsoft does it.

Here’s the new way to hide the “New” button:

   1:  var lookupControl = Sys.Application.findComponent("some_lookupid");
   2:   
   3:  if (lookupControl != null)
   4:  {
   5:      lookupControl._element._behaviors[0].AddParam("ShowNewButton", 0);
   6:  }

Like most of the things on this blog, this is highly unsupported, but I personally believe that this is a harmless hack.  There is one caveat, however, to the above code:

  • The ‘_behaviors’ member is a collection of references to classes.  For every Lookup I could find, there was only one entry, and it exposed the “AddParam” function.  Conceivably, there could be other Lookups with multiple behaviors, and the first item in ‘_behaviors’ may not be the one you want.  You have been warned.

Tuesday, February 5, 2013

Custom CRM 2011 Form Notifications for UR12

[UPDATE: 2013.04.12 I added some additional tricks to this code, at the bottom.]

Before Update Rollup 12, it was relatively simple to use the original “form alert” hack (seen here, here, here, and here) to produce custom, inline alerts and notices for the end user.  It’s a great feature of the form, and I wish I knew why using it is unsupported.

Alas, many realized that these customizations would be undone by Update Rollup 12, and indeed they have.  So, allow me to show you what appears to be the “Microsoft” way of accessing the new form notification system.  The added bonus is that this method requires no additional libraries or external references, and should be cross-browser.  (Disclaimer: the following information was not released or documented by Microsoft; I discovered it after a few hours of pouring over Developer Tools in IE10.)

The original hack could never have been cross-browser, because it relied on the “htc” behavior file which backed the original “crmNotifications” element.  Fortunately, these functions haven’t changed… just moved to a new home.  Here’s the old way (pre-UR12):

var notificationsArea = document.getElementById('crmNotifications');

notificationsArea.AddNotification('noteId1', 1, 'namespace', 'Message.');

And here’s the new way (post-UR12):

var notificationsList = Sys.Application.findComponent('crmNotifications');

notificationsList.AddNotification('noteId1', 1, 'namespace', 'Message.');

Both examples do the same thing in their respective CRM 2011 revisions.  This customization remains as unsupported as it ever was; however there is relatively little danger in using it.

Here are some additional tricks you can use:

notificationList.SetNotifications();

That will reset the notifications array with an empty set.  Also, you can hide the notifications area by using:
notificationList.SetVisible(false);