A fast query edge case that might bite you

There’s been a bit of discussion (I might even go as far as to say ranting 😉 ) on the subject of not using “fast query” in your website code recently. I’m a supporter of this idea – but I came across an issue recently that points out why it’s not always easy to be confident that you’re not making use of it indirectly…

So, for the benefit of Google:

The problem:

I’m doing some work with a client who’s production site makes use of a combination of Sitecore v8.2, Publishing Service and Commerce Connect. They have a very large content tree, and they’d been discussing some publishing performance challenges with Sitecore Support recently. The outcome of that discussion was that Support pointed out they had “update the descendants table” enabled in their publishing config. That operation (the rebuild of the descendants table after each publish) was taking five minutes or so even if you published a single page – and was responsible for most of the delay they were seeing.

After finding this issue in the site’s logs, support suggested disabling this operation. Support asked whether the client had any code that made use of fast query, since the descendants table is used by fast queries to find content. But my client was happy that their code didn’t include any queries like that.

The change helped with the performance issue, and everything was fine for a while. However a while later the client published a new “store” to their public site, and immediately noticed that it crashed as soon as you tried to add a product to your shopping basket.

After some digging they noticed that Commerce Connect’s EaPlanProvider class was the source of their problem. On their newly published site, it was failing to resolve the correct engagement plan for basket operations. After some disassembly and digging through the code behind this, we could see that there were two operations in this code that would fail:

EngagementPlanItem engagementPlanItem = Tracker.DefinitionDatabase.Automation().EngagementPlans[engagementPlanName];

where it tries to find the definition item for the engagement plan, and

EngagementPlanStateItem engagementPlanStateItem = engagementPlanItem.States[stateName];

where it tries to find the right state item in that plan.

Under the surface, both of these lines of code call the Sitecore.Analytics.Data.Items.ItemRecords<TItemType> object’s GetName() method. And when you look at the innards of that:

private TItemType FindByName(string name)
{
    Assert.ArgumentNotNull(name, "name");
    ItemUtil.AssertItemName(name);
    if (root != null)
    {
        string format = deep ? "fast://*[@@id = {0}]//*[@@name = {1}]" : "fast://*[@@id = {0}]/*[@@name = {1}]";
        string query = string.Format(format, EscapeQueryParameter(root.ID.Guid.ToString()), EscapeQueryParameter(name));
        Item[] array = root.Database.SelectItems(query);
        if (array != null && array.Length > 0)
        {
            Item[] array2 = array;
            foreach (Item item in array2)
            {
                if (templateFilter(item))
                {
                    return Wrap(item);
                }
            }
        }
    }
    return default(TItemType);
}

It makes a fast query!

So the client’s problem was that publishing a brand new store also published brand new Engagement Plan items to go with the store. And since Publishing Service is now configured not to update the descendants table, this fast query is never going to return the correct items, and you get a null reference exception…

The consequences…

Since Publishing Service ships with the descendants table update disabled by default, this seems like an issue that could affect other Commerce Connect users too.

So if you’re seeing similar issues when making use of Commerce Connect with publishing service, you’ll need to consider one of two work-arounds:

  • You may need to change the “don’t update descendants” setting so that this table is updated at publish time.
  • Or alternatively you may need to remember to manually update the descendants table (via the “cleanup database” operation available via API calls or the Control Panel UI) each time you add new engagement plans.

I’ve raise a query with Support about this issue, and they’ve accepted that it is a bug in the product. Hopefully we’ll see a fix for this in the not too distant future. But in the meantime, if you have the same problem and want to hurry the fix along, the bug ticket numbers are 291129 and 291130.

Advertisements

2 thoughts on “A fast query edge case that might bite you

  1. Any use, what so ever, of fast: query in the core product should be raised as a bug. Using fast: breaks the very foundation of Sitecore’s own Data Provider model and architecture.

  2. Pingback: What do you mean you can’t fetch that item by its path? | Jeremy Davis

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.