Geode provides APIs to capture a handful of events in a distributed system providing extensive documentation on how to implement listeners and callbacks for processing those synchronously or asynchronously.
This document covers CacheWriter
and CacheListener
best practices for handling CacheEvents
.
[[images/events.png]]
A CacheWriter
is an event handler that synchronously handles “happens-before” events (CacheEvent
) in an ordered fashion. It is mostly used for data validation and in some cases data synchronization with external data sources, offering a write-through capability for regions handling events that can be local, within the same JVM, or remote, in the case of replicated or partitioned region.
CacheWriter
per Region.CacheWriter
can abort operations (fail-fast) and will propagate the CacheWriterException
back to the caller.Available events and callbacks:
beforeCreate(EntryEvent event)- Invoked before an entry is created. beforeUpdate(EntryEvent event) - Invoked before an entry is updated. beforeDestroy(EntryEvent event) - Invoked before an entry is destroyed. beforeRegionClear(RegionEvent event) - Invoked before a region is cleared. beforeRegionDestroy(RegionEvent event) - Invoked before a region is destroyed.
It is not recommended to perform long running operations inside a CacheWriter
within the current thread. If such a long running operation is needed consider processing it asynchronously through an AsyncEventListener
for example. Using an ExecutorService
to delegate that execution to a different thread is possible, but considered an anti-pattern, since it breaks the fail-fast and happens-before concept of this callback.
A CacheListener
is an event handler that synchronously responds to events after modifications occurred in the system. The main use cases for a CacheListener
are synchronous write-behind and notifications, triggering actions after certain modifications occur on a region or on the system. It can handle cache events related to entries (EntryEvent
) and regions (RegionEvent
) but events can be processed in a different order than the order they’re applied in the region.
CacheListener
in the same region.AsynchronousEventListener
.Available events and callbacks:
afterCreate(EntryEvent<K,V> event) - Handles the event of new key being added to a region afterDestroy(EntryEvent<K,V> event) - Handles the event of an entry being destroyed afterInvalidate(EntryEvent<K,V> event) - Handles the event of an entry's value being invalidated afterRegionClear(RegionEvent<K,V> event) - Handles the event of a region being cleared afterRegionCreate(RegionEvent<K,V> event) - Handles the event of a region being created afterRegionDestroy(RegionEvent<K,V> event) - Handles the event of a region being destroyed afterRegionInvalidate(RegionEvent<K,V> event) - Handles the event of a region being invalidated afterRegionLive(RegionEvent<K,V> event) - Handles the event of a region being live after receiving the marker from the server afterUpdate(EntryEvent<K,V> event) - Handles the event of an entry's value being modified in a region
When dealing with Geode callbacks there are some operations that should be avoided or used with extra attention. Some general recommendations are:
FunctionService
, since they can cause distributed deadlocks.CacheListener
if you have conserve-sockets set to true.EntryEvent.getNewValue()
or EntryEvent.getOldValue
can result in deserializations unless PDX and read-serialized=true
are used.CacheListener
or a CacheWriter
are thread-safe and entries are locked for the current thread.When using transactions:
CacheWriter
should not start transactions;CacheWriter
and CacheListener
will receive all individual operations part of a transaction, unlike their transactional counterparts TransactionWriter
and TransactionListener
;CacheWriter
can only be notified by a TransactionWriter
and should handle rollback or failures properly;CacheWriterException
is still propagated to the application and it should handle the failures in the context of the transaction by continuing or aborting; JTA is the recommended alternativeTransactionWriter
instead of a CacheWriter
EntryEvent.getTransactionId()
will return the current internal transaction IDCacheWriter
can be rolled back and participate in the same global transactionWhen dealing with transactions always consider using TransactionListener
or TransactionWriter
for handling transaction events, but do notice that they’re cache-wide handlers.
[[images/cwclflow.png]]