Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • John 79 posts 115 karma points
    Jul 15, 2013 @ 12:50
    John
    0

    Firing an event on each load-balanced node when publishing

    We have two web servers with "distributedCalls" enabled so that they keep their caches up to date.

    I would like to fire an event when someone publishes a page, but I would like that event to fire on both web servers (so I can update another cache that I am using).

    We are upgrading to Umbraco 6.1.1.  When I looked into this a while ago (an earlier Umbraco 6.x build) I could have sworn I found an event that fires when the cache is updated, but I can't for the life of me find it anywhere now I'm in a position to use it.  (Doh!)

    I don't suppose anyone can point me in the right direction could they?  Or if there's an alternative way.  I'm hoping it's right under my nose and I'm just not seeing it.

    I know I could write my own thing to look at the distributed list and fire off web service calls etc. but I'd like to keep it as simple as I can, so I'm hoping there's something built-in to do this.

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 8x c-trib
    Jul 16, 2013 @ 08:01
    Lars-Erik Aabech
    0

    Events doc is here:
    http://our.umbraco.org/documentation/Reference/Events/application-startup
    (Quick google-fu ;) )

    You could possibly use serverside SignalR to tell the other server(s) that new content is published.
    http://www.asp.net/signalr

    Lars-Erik

  • John 79 posts 115 karma points
    Jul 16, 2013 @ 09:42
    John
    0

    Thanks for the reply.

    Just to clarify, my issue isn't how to register an event, it's how to have the event trigger on both servers.  I can register a publish event no problem, but that's not quite what I'm after unless I do some kind of web servicey type call as per distributed calls (or something like SignalR).  Ideally I would like to avoid that if there is a simpler way.

    I am convinced that there was an event in there somewhere and am frustrated with myself for not making a note of it!

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 8x c-trib
    Jul 16, 2013 @ 09:54
    Lars-Erik Aabech
    0

    I don't know about that. I'd be surprised though. :)

    Triggering an event on both servers from a database event would need stuff that Umbraco can't support since it supports multiple database platforms, and SignlaR and it's like isn't bundled. Could be that something polls the database, though, but I don't know about that. Might be there's a package that does it.

    However, if you subscribe to the published event and write some SignlaR code, I'm convinced you can get away with less than 30 lines of C#. ;)

    (I think there's a way to turn off the content cache xml file, but I'm sure you don't want to do that.)

  • John 79 posts 115 karma points
    Jul 17, 2013 @ 11:12
    John
    0

    Thanks again for the reply.

    With distributed calls, when I publish a page a web service call is made to each of the two nodes telling them to update their cache.  I wouldn't have though it would be out of the question for an event to be raised by each at that point.  I will have to have a bigger dig into the source to see what's going on.  (I had a quick look but wasn't entirely sure.)  Don't think it's really anything to do with the database.

    The reason I want to avoid SignalR or anything like that is that regardless of how little code it might need, it still adds extra complexity and more noise on the server which I would like to keep to a minimum.

    I suspect I will have to do that kind of thing though, but want to make sure there isn't something nice and simple I can do instead first.

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 8x c-trib
    Jul 17, 2013 @ 13:22
    Lars-Erik Aabech
    0

    Right, I'm fairly new to Umbraco myself, so haven't looked into anything called "distributed calls" (?).

    If there's already something that does that I'd be surprised if there isn't an event when the cache is cleared and stuff is republished.
    Sure the one(s) I linked to aren't raised?

    As long as it's the servers that has to do the service calls, I guess you can do it without SignalR. They can enroll with each other or through some coordinator/master server. Shouldn't be too difficult to set up. (Configure a list of all servers IPs on all servers and make them call each other)

    I'd be happy to hear what you end up with, we're probably going to need something like that ourselves. :)

  • John 79 posts 115 karma points
    Jul 17, 2013 @ 16:03
    John
    0

    For normal Umbraco stuff you can edit umbracoSettings.config and there's a <distributedCall> section.  If you set this to be enabled you can then list out a series of servers.  (There are examples in the comments).

    What this means is that if you publish a page on one server, web service calls are made to each server in your farm telling them about it so that they can update their caches.  (You still need replication of the media folders - we use DFS for this I think.)

    For most load-balanced environments this should be enough but I've also got some other bespoke bits and bobs which is why I need to do something similar to update my own cache.  I've got a few options - I've not had time to look into it since my original post but should hopefully have a look again soon.  I'll update this if I get anywhere.

  • John 79 posts 115 karma points
    Jul 17, 2013 @ 16:05
    John
    0

    (Oops - double post, sorry!)

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 8x c-trib
    Jul 17, 2013 @ 16:44
    Lars-Erik Aabech
    100

    Ah, cool. Nice to know about.

    I have the core code open and did a 5 minute browse of the code.
    Here's the event: :)

    umbraco.presentation.content.AfterUpdateDocumentCache

    (static)

  • John 79 posts 115 karma points
    Jul 17, 2013 @ 17:05
    John
    0

    Ahhh that looks like it!  I tried Content with a capital "C" but not a lowercase one.  My searching skills are clearly not up to much!

    I'll give that a go and post back on here about how I get on.  Thank you so much!!

  • John 79 posts 115 karma points
    Jul 17, 2013 @ 17:06
    John
    0

    Ahhh that looks like it!  I tried Content with a capital "C" but not a lowercase one.  My searching skills are clearly not up to much!

    I'll give that a go and post back on here about how I get on.  Thank you so much!!

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 8x c-trib
    Jul 17, 2013 @ 17:09
    Lars-Erik Aabech
    0

    For now I think every element of the Umbraco "domain model" has at least three implementations each, either with different namespace or different casing.

    Best way of searching is Resharper > Ctrl+T / Ctrl+Shift+T / F12 / Mouse thumb and just surf. :)
    (And sometimes bruteforcing with Ctrl+Shift+F)

    I learned a lot by this, so thanks yourself!

  • John 79 posts 115 karma points
    Jul 19, 2013 @ 11:56
    John
    0

    I've spent a little time with this now.  Although I've not got load balanced servers set up at the moment in dev so haven't proven that this works in particular, it does seem to work fairly well.  (I was using Document_AfterPublish initially and had some problems which have now gone away).

    A few things worth noting:.

    • if you unpublish or delete a page this event doesn't get called.  Instead you need "AfterClearDocumentCache".  So in my case I subscribed to both and they work great.
    • If you publish a parent and choose to publish all unpublished children it will call the event for each child node.
    • But if you have a published node and then unpublish its parent, it will not call the event for the children.  So I guess in this case I will need to call Descendants and see if there's anything there I'm interested in.
    • This uses the old Document API not the new content service API.  I am just in the process of upgrading our 4.7.2 site to 6.1.1 and we have used Document heavily and found that Document is now seriously buggy.  I have rewritten a lot of stuff to use the new service and it works great (it is a big improvement over the original).  I suspect when I come to look at the descendants I will need to use a mixture of the two APIs.  (IE register the event with Document but then look at the descendants using the ContentService.)  I've not verified that but from current experience the Document API in 6.1.1 isn't so much obsolete as totally broken.  Hopefully these events will be migrated to the new API in the future.

    Anyway, thanks very much for your help - it feels like this has done the trick.

     

     

  • Peter Duncanson 430 posts 1360 karma points c-trib
    Jul 19, 2013 @ 14:31
    Peter Duncanson
    0

    A little side note but I wonder if you could have a CacheDependancy on the umbraco.config file? Can't remember if that gets updated every time but might be worth checking, it might cover some of your other issues too. Only trouble is it only tells you that "something" changed and not what but that might be enough to renew your cache?

  • John 79 posts 115 karma points
    Jul 19, 2013 @ 15:31
    John
    0

    That's an interesting idea!  Although I would really prefer to only update if I have to.  I started to look at the descendant stuff but it occurred to me that in my case having stale entries in the cache isn't really that big a problem, particularly because it will catch up eventually anyway.  So I've left it.  It seems to work pretty well.

  • John 79 posts 115 karma points
    Sep 17, 2013 @ 10:42
    John
    2

    I noticed a problem with this in that if I right click the "Content" node and republish the entire site, this event wasn't firing.

    Rummaging around the source I found another way that appears to work in either case and also uses the newer API:

    PageCacheRefresher.CacheUpdated += PageCacheRefresher_CacheUpdated;
    

    This event is triggered if something is either added to, or removed from, the cache. The event handler signature looks like this:

    void PageCacheRefresher_CacheUpdated(PageCacheRefresher sender, CacheRefresherEventArgs e)
    

    If refreshing all content then e.MessageType will equal MessageType.RefreshAll and e.MessageObject will be null. Otherwise e.MessageObject will contain the thing being updated - it's of type "object". In my testing it seems to be of type IContent so I've done "e.MessageObject as IContent" and checked against nulls just in case it comes through as something else.

    I haven't tested it in a load balanced environment yet but from looking at the code it does seem to be triggered by distributed calls if they are enabled so I am reasonably sure it would work.

  • Comment author was deleted

    Nov 11, 2013 @ 21:45

    FWIW, this has been a great read for the same issue that I have.

  • Dan Diplo 1554 posts 6205 karma points MVP 6x c-trib
    Jan 24, 2014 @ 10:49
    Dan Diplo
    0

    Yes, this thread has been a potential life saver for me too as I was stuck with a similar problem.

    This is based on Umbraco 6.1.6

    For the record John's hunch was right - the PageCacheRefresher.CacheUpdated is raised by distributed calls in a load balance envrionment. I registered it in the OnApplicationStarted event.

    One thing I found was different to John was that e.MessageObject was being sent as an Int32 and was the ID of the content node being updated.

    In a bulk publish the PageCacheRefresher.CacheUpdated event was triggered once for every node being updated (so if ten nodes are published it is raised ten times).

Please Sign in or register to post replies

Write your reply to:

Draft