In Sitecore 9 the event model has changed somewhat and events are now
queued within each DB (master, core, web etc).
This is partially correct. You could always queue remote events in your Sitecore database of choice. Sitecore 9 still has a concept of a preferred event queue database.
Two options for queueing a remote event
Sitecore.Eventing.EventManager.QueueEvent<T>(remoteEvent);
(this is now obsolete in Sitecore 9, see the next section explaining the preferred approach)
- This inserts a remote event into the EventQueue table defined in configs:
<add name="sitecore" type="Sitecore.Eventing.EventProvider, Sitecore.Kernel" systemDatabaseName="core"/>
Sitecore.Configuration.Factory.GetDatabase("web").RemoteEvents.EventQueue.QueueEvent(remoteEvent);
- Choose your database. This can help reduce the number of records in the systemDatabase. Also helpful if your remote event is tied to a specific database, such as
web
.
Sitecore 9 Updates For Option 1 Above
In Sitecore 9, if you wish to leverage the defaultEventQueue
for your event, you need to rely on DI to help you out. Use the ServiceLocator pattern or Constructor Injection. Example:
public class MyController{
private readonly IEventQueue _eventQueue;
public MyController(IEventQueue eventQueue)
{
_eventQueue = eventQueue;
}
public void MyMethod(){
_eventQueue.QueueEvent<MyType>(myTypeInstance); // plus overload for global and local declaration
}
}
You are able to swap out the provider to an Async version via ~\App_Config\Include\Examples\Sitecore.Publishing.EventQueueProvider.Async.config.example
without modifying your code.
It is also worth mentioning that 9.2 contains modifications to the defaultEventQueue
config entries:
<eventing>
<!-- EVENT QUEUE -->
<eventQueueProvider defaultEventQueue="core">
<eventQueue name="web" type="Sitecore.Data.Eventing.$(database)EventQueue, Sitecore.Kernel">
<param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)" />
<param ref="PropertyStoreProvider/store[@name='$(name)']" />
</eventQueue>
<eventQueue name="master" type="Sitecore.Data.Eventing.$(database)EventQueue, Sitecore.Kernel" role:require="!ContentDelivery">
<param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)" />
<param hint="" ref="PropertyStoreProvider/store[@name='$(name)']" />
</eventQueue>
<eventQueue name="core" type="Sitecore.Data.Eventing.$(database)EventQueue, Sitecore.Kernel" role:require="!ContentDelivery">
<param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)" />
<param ref="PropertyStoreProvider/store[@name='$(name)']" />
</eventQueue>
</eventQueueProvider>
<eventQueueProvider role:require="ContentManagement or ContentDelivery">
<patch:attribute name="defaultEventQueue">web</patch:attribute>
</eventQueueProvider>
</eventing>
Notice the inclusion of ContentManagement or ContentDelivery
. This
change is absent in 9.0-9.1 as evidenced by @Gatogordo's post:
https://ggullentops.blogspot.com/2019/03/eventqueue-in-sitecore-91.html
var args = new Testing.Events.MyEventArgs();
Sitecore.Events.Event.RaiseEvent("testing:myevent", args);
This code is targeting a "local" event, such as "publish:end:remote". It's intrinsically decoupled from the previous code which queue's remote events. Raising an event specifically targets a local event specified in the config on the executing server.
The reason the two are often discussed in unison is that many remote events call a local event during execution.
I'm confused as to what/how to create the object someObject. The
QueueEvent method has two signatures:
QueueEvent(RemoteEventArgs event)
QueueEvent(RemoteEventArgs event, bool addToGlobalQueue, bool
addToLocalQueue)
someObject
can be any class that is serializable, literally. Any given Event Queue can hold 2GB of serializable data per record. Obviously, don't do this, but it's possible.
I don't understand how the event object passed to QueueEvent
identifies the name of the event. I also don't see how the event could
be identified magically by passing in a specific event arg type.
Remote events are subscribed to, typically upon initialization. The subscription targets the type of the object. As previously mentioned, make sure your type is serializable (with DataContract
, DataMember
, etc.), and then add a subscription to target that type.
To see this for yourself, review this config entry in the <initialize>
pipeline and decompile the source:
<processor type="Sitecore.Eventing.Remote.RemoteEventMap, Sitecore.Kernel" method="InitializeFromPipeline">
<param desc="eventQueue" ref="eventing/eventQueueProvider/eventQueue[@name='core']" role:require="(Standalone or Reporting or Processing) and !ContentManagement and !ContentDelivery" />
<param desc="eventQueue" ref="eventing/eventQueueProvider/eventQueue[@name='web']" role:require="ContentManagement or ContentDelivery" />
</processor>
When the event queue's are read (by default every 2 seconds), each server will pull the latest unread events applicable to their server, then compare the data types with the known types in their subscription map. If there is a match, it executes the method specified in the subscription.
I explain most of this in concise detail at my blog post: https://sitecorerap.wordpress.com/2017/12/29/simple-remote-events-in-sitecore/
systemDatabase
and instead want you to queue events in your database of choice.