An AsyncEventListener receives callbacks for events that change region data. You can use an AsyncEventListener implementation as a write-behind cache event handler to synchronize region updates with a database.
An AsyncEventListener instance is serviced by its own dedicated thread in which a callback method is invoked. Events that update a region are placed in an internal AsyncEventQueue, and the dedicated thread dispatches a batch of events at a time to the listener implementation.
You can configure an AsyncEventQueue to be either serial or parallel. A serial queue is deployed to one GemFire member, and it delivers all of a region's events in order to a configured AsyncEventListener implementation. A parallel queue is deployed to multiple GemFire members, and each instance of the queue simultaneously delivers region events to a local AsyncEventListener implementation.
A parallel queue provides the best throughput for writing events, they provide less control for ordering those events. With a parallel queue, you cannot preserve event ordering for a region as a whole because multiple GemFire servers queue and deliver the region's events at the same time. However, the ordering of events for a given partition (or in a given queue of a distributed region) can be preserved.
For both serial and parallel queues, you can control the maximum amount of memory that each queue uses, as well as the batch size and frequency for processing batches in the queue. You can also configure queues to persist to disk (instead of simply overflowing to disk) so that write-behind caching can pick up where it left off when a member shuts down and is later restarted.
Optionally, each queue can use multiple threads to dispatch queued events. When you configure multiple threads for a queue, the logical queue that is hosted on a GemFire member is divided into multiple physical queues, each with a dedicated dispatcher thread. You can then configure whether the threads dispatch queued events by key, by thread, or in the same order in which events were added to the queue.
To receive region events for processing, you create a class that implements the AsyncEventListener interface. The processEvents method in your listener receives a list of queued AsyncEvent objects in each batch.
Each AsyncEvent object contains information about a region event, such as the name of the region where the event occurred, the type of region operation, and the affected key and value.
class MyAsyncEventListener implements AsyncEventListener {
public void processEvents(List<AsyncEvent> events) {
// Process each AsyncEvent
for(AsyncEvent event: events) {
// Write the event to a database
}
}
}
To configure a write-behind cache listener, you first configure an asynchronous queue to dispatch the region events, and then create the queue with your listener implementation. You then assign the queue to a region in order to process that region's events.
<cache>
<async-event-queue id="sampleQueue" persistent="true"
disk-store-name="exampleStore" parallel="false">
<async-event-listener>
<class-name>MyAsyncEventListener</class-name>
<parameter name="url">
<string>jdbc:db2:SAMPLE</string>
</parameter>
<parameter name="username">
<string>gfeadmin</string>
</parameter>
<parameter name="password">
<string>admin1</string>
</parameter>
</async-event-listener>
</async-event-queue>
...
</cache>
Cache cache = new CacheFactory().create();
AsyncEventQueueFactory factory = cache.createAsyncEventQueueFactory();
factory.setPersistent(true);
factory.setDiskStoreName("exampleStore");
factory.setParallel(false);
AsyncEventListener listener = new MyAsyncEventListener();
AsyncEventQueue asyncQueue = factory.create("customerWB", listener);
On each GemFire member that hosts the AsyncEventQueue, assign the queue to each region that you want to use with the AsyncEventListener implementation.
<cache>
<region name="data">
<region-attributes async-event-queue-ids="sampleQueue">
</region-attributes>
</region>
...
</cache>
RegionFactory rf1 = cache.createRegionFactory();
rf1.addAsyncEventQueue(asyncQueue);
Region customer = rf1.create("Customer");
// Assign the queue to multiple regions as needed
RegionFactory rf2 = cache.createRegionFactory();
Region order = rf2.create("Order");
AttributesMutator mutator = order.getAttributesMutator();
List<AsyncEventQueue> asyncQueues = cache.getAsyncEventQueues();
for(AsyncEventQueue asyncQueue: asyncQueues) {
if(asyncQueue.getId().equals("customerWB")) {
mutator.addAsyncEventQueue(asyncQueue);
}
}
See the GemFire API documentation for more information.
The AsyncEventListener receives events from every region configured with the associated AsyncEventQueue.