Skip to content

Instantly share code, notes, and snippets.

@drpeck
Created August 31, 2017 08:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drpeck/fbaf6f8f3acb58b834dc8947aae1083e to your computer and use it in GitHub Desktop.
Save drpeck/fbaf6f8f3acb58b834dc8947aae1083e to your computer and use it in GitHub Desktop.
Hack/ workaround to Umbraco Courier not being updated on slave servers
public class CourierUmbracoEvents : ApplicationEventHandler
{
//Wait 5 seconds after an examine index before trying to republish what has been indexed
private const int DelayAfterIndex = 5 * 1000;
//Give a republishe 2 minutes to complete
private const int IndexTimeout = 120 * 1000;
private Guid _lastIndexId;
private List<int> _indexedContentIds = new List<int>();
private Dictionary<int, DateTime> _republishRegister = new Dictionary<int, DateTime>();
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
LogHelper.Info<CourierUmbracoEvents>("CourierUmbracoEvents init");
var serverRegistrar = ServerRegistrarResolver.Current.Registrar as IServerRegistrar2;
if (serverRegistrar == null || serverRegistrar.GetCurrentServerRole() != ServerRole.Master)
{
LogHelper.Info<CourierUmbracoEvents>("CourierUmbracoEvents exiting because not master");
return;
}
//Listening to all NodeIndexed on ExternalIndexer (Courier extracting events aren't firing)
foreach (var indexProvider in ExamineManager.Instance.IndexProviderCollection
.OfType<BaseIndexProvider>()
.Where(x => Constants.Examine.ExternalIndexer == x.Name))
{
LogHelper.Debug<CourierUmbracoEvents>("Listening to NodeIndexed for ExternalIndexer");
indexProvider.NodeIndexed += (sender, e) => NodeIndexed(e.NodeId);
}
}
private void NodeIndexed(int nodeId)
{
LogHelper.Debug<CourierUmbracoEvents>("IndexProvider_NodeIndexed called for nodeId: " + nodeId);
ClearTimeoutsOnRepublishRegister();
if (_republishRegister.ContainsKey(nodeId) == true)
{
LogHelper.Debug<CourierUmbracoEvents>("Not scheduling a republish for {0} as we have an active timeout for it", () => nodeId);
return;
}
_indexedContentIds.Add(nodeId);
//Make a reference to the most recent index
var indexId = Guid.NewGuid();
_lastIndexId = indexId;
//After a second, check if the session has ended
Task.Run(() => { PauseAfterExamineIndex(indexId); });
}
private async void PauseAfterExamineIndex(Guid indexId)
{
//Pause to wait for courier to complete, and avoid clashes
await Task.Delay(DelayAfterIndex);
LogHelper.Debug<CourierUmbracoEvents>("AfterExamineIndex running after a {0} delay", () => DelayAfterIndex);
//Don't republish if there has been another index while we've been sleeping
if (_lastIndexId != indexId)
return;
int[] ids;
lock (this)
{
//Get a distinct list of ides requested for republish
ids = _indexedContentIds.Distinct().ToArray();
//and wipe the list for next time
_indexedContentIds.Clear();
}
LogHelper.Debug<CourierUmbracoEvents>("Scheduling a republish to avoid Courier issue with ids '{0}'", () => string.Join(",", ids));
Republish(ids);
}
private void Republish(int[] nodeIds)
{
if (nodeIds.Any() == false)
return;
//Set the time for valid node
foreach (var nodeId in nodeIds)
{
_republishRegister[nodeId] = DateTime.Now;
}
var serverRegistrar = ServerRegistrarResolver.Current.Registrar as IServerRegistrar2;
if (serverRegistrar == null)
{
LogHelper.Debug<CourierUmbracoEvents>("serverRegistrar is null");
return;
}
LogHelper.Debug<CourierUmbracoEvents>("Performing distributed refresh for: {0}", () => string.Join(", ", nodeIds));
ServerMessengerResolver.Current.Messenger.PerformRefresh(serverRegistrar.Registrations, new PageCacheRefresher(), nodeIds);
}
private void ClearTimeoutsOnRepublishRegister()
{
var threshold = DateTime.Now.AddMilliseconds(IndexTimeout * -1);
_republishRegister.RemoveAll(o => o.Value < threshold);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment