SaaS CMS has officially launched! Learn more now.

Reacting to publish event on all instances

Vote:
 

Using EPiServer 11.8

We are running a load balanced setup.

I would like to react to a "published" event on all the servers. So if someone published a page, I want all the instances to react to that.

How would I go about doing that?

This example seems to only react to the event on the server that is doing the publishing? 
https://world.episerver.com/blogs/Janaka-Fernando/Dates/2015/4/adding-custom-logic-to-your-publishing-step/

#194297
Jun 19, 2018 10:23
Vote:
 

You can send your own event message with the built-in API when a page is published, please see https://world.episerver.com/documentation/developer-guides/CMS/event-management/Event-Management-API/.

You can also use e.g. MSMQ, Service Bus, RabbitMQ or similar.

#194299
Jun 19, 2018 10:34
Vote:
 

Ok, so I need to distribute the event myself, and not subscribe to a built in one?

#194300
Jun 19, 2018 10:35
Vote:
 

Yes. The only built-in events are for cache invalidation. And that's not really what you want here if I understand you correctly.

You need to subscribe to an event, like the link in your first post, then distribute it to all your subscribers. If you're not planning to base your whole architecture arround messaging, I would go with the event management that's shipped with Episerver, otherwise I would recommend Akka .NET. 

#194302
Jun 19, 2018 10:42
Vote:
 

Hmm, "EventRegistry.Instance" is internal, so I cannot use that sample?

#194303
Jun 19, 2018 10:42
Vote:
 

Sidenote, if your solution is running in DXC Service you aldready have access to Service Bus. Then I would use that API instead.

#194304
Jun 19, 2018 10:43
Vote:
 

I would assume there is an interface with a service registered in the container that you can use instead.

#194305
Jun 19, 2018 10:45
Vote:
 

You can still use internal APIs, but they are subject to breaking changes without any new major version.

#194306
Jun 19, 2018 10:46
Vote:
 

Something like this looks like it works?

Now I need to test on a distributed setup.

    [InitializableModule]
    [ModuleDependency(typeof(InitializationModule))]
    public class InitializeEvents : IInitializableModule
    {
        private static readonly Guid RaiserId = new Guid("03D1D3EC-7D4C-4BA4-8916-48872C7A8422");
        private static readonly Guid EventId = new Guid("CA65980C-206C-4D89-9AB6-49DA6A04C8BC");

        public void Initialize(InitializationEngine context)
        {
            // Subscribe to the custom events
            var eventRegistry = ServiceLocator.Current.GetInstance<IEventRegistry>();
            eventRegistry.Get(EventId).Raised += OnRaised;

            // Subscribe to publishing events
            var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
            contentEvents.PublishedContent += ContentEventsOnPublishedContent;
        }

        private void ContentEventsOnPublishedContent(object sender, ContentEventArgs contentEventArgs)
        {
            IContent content = contentEventArgs.Content;
            if (content is ProjectPage || content is ProjectFolder)
            {
                // Rais the cache clearing event
                var eventRegistry = ServiceLocator.Current.GetInstance<IEventRegistry>();
                eventRegistry.Get(EventId).Raise(RaiserId, true);
            }
        }

        private void OnRaised(object sender, EventNotificationEventArgs eventNotificationEventArgs)
        {
            //React to the cache clearing event
        }

        public void Uninitialize(InitializationEngine context)
        {
            
        }
    }
#194312
Jun 19, 2018 11:16
Vote:
 

The comments in your code are about cache invalidation? So what are you really trying to achieve here? If you want stuff to happen when cache is invalidated for e.g. a page, then you don't need this code. Then you can probably just use the same cache keys as master keys for your own cached objects.

#194315
Jun 19, 2018 11:21
Vote:
 

My scenario is that I'm caching a list of Projects in memory on each server instance. So whenever a page of that type is published, I need to refresh that list in memory.

#194317
Jun 19, 2018 11:24
Vote:
 

In that case you only need to invalidate the cache on one machine. Then this will be replicated on all machines given that you have configured the events correctly (I assume you have since you're already running a load-balanced environment) and using Episerver's cache API (ISynchronizedObjectInstanceCache) for caching your projects.

#194337
Jun 19, 2018 11:30
Vote:
 

That approach would typically mean that a user would have to take the hit to populate the cache on the first request after invalidating it, if I understand correctly?

I would like to populate it up front when the content changes. 

#194340
Jun 19, 2018 11:39
Vote:
 

ISynchronizedObjectInstanceCache is a wrapper around the regular cache, which has events for when items are removed. So you should be able to populate the cache again as soon as the items are removed. I wouldn't bother with that though and let the first request take that hit instead.

#194352
Jun 19, 2018 13:13
Vote:
 

Thanks for the input. I will need to measure a bit on what the actual performance is when filling the cache, and then determine if I need to pre seed it or not.

But now I have options at least :)

#194353
Jun 19, 2018 13:23
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.