Help! Sitecore History Engine does not index some of my items!

16 May 2013
Adam Najmanowicz
Frink_Cognifide_2016_HeaderImages_0117
Sitecore Calendar
We, together with our client, have run into an issue with the Sitecore History Engine recently. The story is fairly simple yet coming to a conclusion was not that obvious. Some of our articles did not index in a multi-management server scenario properly. When articles were edited on one server, the second one didn't always pick up and index the changes.

 The scenario is as follows:
  • We have a search based application delivered on top of Sitecore.
  • The application supports business with entering articles, collecting feeds and otherwise getting content into Sitecore.
  • The ingestion happens on the Content Management (CM) servers which are load balanced.
  • From time to time articles edited on one of the servers don’t make their way into our Lucene indexes on the other machine.
  • Editors assigned by Load Balancer to the other server sometimes can’t see the changes made on the other server.
  • We have the History Engine enabled and set up to support the multi-server scenario.
My first two thoughts are:
  • Race condition and timing issues between those two servers or…
  • Content issue (I’ve ruled that out pretty quickly as this would result in not indexing the article on the other server either).
So what happens? How does the Sitecore History Engine synchronizes between servers?

How history entries are committed

When you dig into the HistoryEngine class you will see that the AddEntry method instantiates the entry as follows:
HistoryEntry entry = new HistoryEntry(category, action, item,
                                      oldParentId, additionalInfo)
and then the constructor assigns the Sitecore server date/time to the entry:
this.m_created = DateTime.UtcNow;
 

How history entries are consumed

The IndexingProvider initiates the history consumer in the following way:
public virtual void UpdateIndex(Database database)
{
  Assert.ArgumentNotNull((object) database, "database");
  lock (this._lockSet.GetLock((object) database.Name))
  {
    DateTime local = this.GetLastUpdateDate(database);
    this.UpdateIndex(database, local);
  }
}
which determines the Last index update time for the database – the value is pulled from the Properties table. But that date is saved in the Index class in the Rebuild method in the following way:
public virtual void Rebuild(Database database)
{
  // init code ..

  DateTime utcNow = DateTime.UtcNow;

  // reindexing code ...

  database.Properties[IndexingManager.LastUpdatePropertyKey] =
    DateUtil.ToIsoDate(utcNow);
}
You can probably start seeing the problem already... The code uses local server dates to determine entries to pickup. The good thing is that it takes the time from before the index rebuild, but this will still work only if your server times are synchronized to a time-period below the time it takes to rebuild your index.

Get the chronology straight…

How does the timeline looks like then for a following scenario:
  • Two servers in farm synchronizing index,
  • Server_1 has proper time – rebuilds the index based on the history table,
  • Server_2 is 5 seconds late – the article is being saved right after the index was triggered for rebuild,
  • Index rebuild trigger is set to update the index every 30 seconds.

Unindexed change timeline

So what is this all about?

Basically if you use Sitecore search/indexing in a distributed scenario and you're going to rely on the index in your daily activities and  you're going to rely on the History Engine - you need to make sure that your time is synchronized and your time zones are set properly or you might start seeing items not being picked up by your index.