Example using CachingEventSourcingRepository with a cache

Hi,

can someone show an example using CachingEventSourcingRepository, including the setup of a cache (Spring wiring…) I see it mentioned in the documentation, but hard to find a concrete example of it (maybe also add it to the documentation when documented here?:wink: )

Thanks in advance:)

Regards,
Viggo

Hi Viggo,

cache configuration is a feature under improvement currently (see http://issues.axonframework.org/youtrack/issue/AXON-81)

This is how you can configure an EhCache using Spring:

<axon:event-sourcing-repository id=“myCachedRepository” cache-ref=“myCache”
aggregate-type=“com.mycompany.MyAggregate”/>

Cheers,

Allard

Hi,

I tried your example, also adding various dependencies to pom.xml, but ended up with this:
“Error creating bean with name ‘myCache’ defined in class path resource [spring-context.xml]: Unsatisfied dependency expressed through constructor argument with index 1 of type [net.sf.ehcache.jcache.JCacheManager]: Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments?”

from pom.xml:

net.sf.ehcache ehcache-core 2.6.6 net.sf.ehcache ehcache-jcache 1.5.0-0.5

Any clue?

Perhaps you need to do something like

<axon:event-sourcing-repository id=“testCacheRepository” cache-ref=“mockCache” lock-manager=“nullLockManager”
aggregate-factory=“mockFactory”
event-bus=“eventBus” event-store=“eventStore” conflict-resolver=“conflictResolver”>
<axon:snapshotter-trigger event-count-threshold=“50” snapshotter-ref=“snapshotter”/>
</axon:event-sourcing-repository>

**** **** **** **** ****

I must have a proper working sample somewhere. When I have time, I will look it up.

Cheers,

Allard

Thanks Allard, then I’ll be waiting for an update from you:) Could you also at the same time check the version of the dependencies so they’re not the source for problems:)

Cheers,
Viggo

This is what I could find in an actual project:

dependencies:

net.sf.ehcache ehcache-jcache 1.2 net.sf.ehcache ehcache-core 2.5.1

Spring config:

The repository just references the gameCache bean.

Gamecache.xml:

<ehcache xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance

xsi:noNamespaceSchemaLocation=“http://ehcache.org/ehcache.xsd
name=“gameCacheManager”
updateCheck=“false”>

Cheers,

Allard

Thanks Allard!

I applied your example to my application and it worked:) I have a Runner creating a PurchaseOrder with a command, and then update the PurchaseOrder with 4 other command (resulting in a total of 5 events), I loop this 100000 times, and the first time it took 37 seconds, next time it took 55 seconds, then it took 104 second, and then I got this one:

04 sep 2013 13:00:04 ERROR SimpleCommandBus - Processing of a ConfirmTransportVolumCommand resulted in an exception:
net.sf.ehcache.CacheException: java.io.EOFException
at net.sf.ehcache.store.disk.DiskStorageFactory.retrieve(DiskStorageFactory.java:939)
at net.sf.ehcache.store.disk.Segment.decode(Segment.java:167)
at net.sf.ehcache.store.disk.Segment.put(Segment.java:444)
at net.sf.ehcache.store.disk.DiskStore.put(DiskStore.java:477)
at net.sf.ehcache.store.FrontEndCacheTier.put(FrontEndCacheTier.java:257)
at net.sf.ehcache.Cache.putInternal(Cache.java:1489)
at net.sf.ehcache.Cache.put(Cache.java:1417)
at net.sf.ehcache.Cache.put(Cache.java:1382)
at net.sf.ehcache.jcache.JCache.put(JCache.java:637)
at net.sf.ehcache.jcache.JCache.put(JCache.java:606)
at org.axonframework.eventsourcing.CachingEventSourcingRepository$CacheUpdatingUnitOfWorkListener.afterCommit(CachingEventSourcingRepository.java:152)
at org.axonframework.unitofwork.UnitOfWorkListenerCollection.afterCommit(UnitOfWorkListenerCollection.java:65)
at org.axonframework.unitofwork.DefaultUnitOfWork.notifyListenersAfterCommit(DefaultUnitOfWork.java:230)
at org.axonframework.unitofwork.DefaultUnitOfWork.doCommit(DefaultUnitOfWork.java:145)
at org.axonframework.unitofwork.NestableUnitOfWork.commit(NestableUnitOfWork.java:51)
at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:137)
at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:103)
at org.axonframework.commandhandling.SimpleCommandBus.dispatch(SimpleCommandBus.java:70)
at org.axonframework.commandhandling.gateway.AbstractCommandGateway.sendAndForget(AbstractCommandGateway.java:78)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$DispatchOnInvocationHandler.invoke(GatewayProxyFactory.java:391)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$DispatchOnInvocationHandler.invoke(GatewayProxyFactory.java:351)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$FireAndForget.invoke(GatewayProxyFactory.java:554)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$NullOnTimeout.invoke(GatewayProxyFactory.java:459)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$NullOnInterrupted.invoke(GatewayProxyFactory.java:477)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$WrapNonDeclaredCheckedExceptions.invoke(GatewayProxyFactory.java:434)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$GatewayInvocationHandler.invoke(GatewayProxyFactory.java:334)
at com.sun.proxy.$Proxy10.send(Unknown Source)
at com.navarsete.stand012.wholesaler.PurchaseOrderRunner.run(PurchaseOrderRunner.java:47)
at com.navarsete.stand012.wholesaler.PurchaseOrderRunner.main(PurchaseOrderRunner.java:30)
Caused by: java.io.EOFException
at java.io.RandomAccessFile.readFully(RandomAccessFile.java:416)
at java.io.RandomAccessFile.readFully(RandomAccessFile.java:394)
at net.sf.ehcache.store.disk.DiskStorageFactory.read(DiskStorageFactory.java:372)
at net.sf.ehcache.store.disk.DiskStorageFactory.retrieve(DiskStorageFactory.java:937)
… 28 more
2055050 in 68 seconds
DETAILS:

So a couple of observations:

  1. Using the cache, it’s MUCH faster, think I measured the same round without caching and it took nearly 3 minutes! (now 37 seconds, at least the first time).
  2. Any clue why it’s getting slower and slower, and eventually fails?

Cheers,
Viggo

1st run: 37 seconds
2nd run: 55 seconds
3rd run: 104 seconds
4th run: crash
5th run: 89 seconds
6th run: 74 seconds
7th run: crash

Hi Viggo,

I notice that you’re using disk storage for the cache. That kind of beats the purpose of the cache. When you store information on disk, you’re generally better off using snapshots.
Since the disk store seems to be running out of disk space, what kind of information do you store in your aggregate? Is there a list in there getting bigger? That might explain the times for storing the data becoming longer (since it needs to serialize more data each time).

Cheers,

Allard

Thanks for feedback and advices Allard:)

I’m still a newbie to CQRS and Axon in general, so all best practices are highly appreciated:)

Do you mean to have both a cache and a snapshotter applied to the event sourcing repository, like this:

<axon:event-sourcing-repository id=“purchaseOrderRepository”
aggregate-type=“com.foo.PurchaseOrder”
event-bus=“eventBus”
event-store=“eventStore”
cache-ref=“myCache”>
<axon:snapshotter-trigger event-count-threshold=“50” snapshotter-ref=“snapshotter”/>
</axon:event-sourcing-repository>

Questions:

  1. Since each aggregate (PurchaseOrder) will have at most 5 events, what would be best values to put on the different configuration elements?
  2. Should I only have a snapshotter, and not a cache?
  3. About caching…currently writing the cache to a file, I feel you suggest it should be stored in-memory instead, how to do it?

Thanks in advance:)

Hi Viggo,

if you have aggregate that live for a longer period of time (persisting hundreds of events), a snapshotter is really recommended. The threshold that suits your application best is something you should find out using load tests. A couple of hundred events is generally fine.

A cache is recommended when aggregates are subject to periods of high activity. Since your aggregate can be easily loaded from disk using the snapshot, you don’t want the cache to store to disk. Just set overflowToDisk to false in your ehcache config. Check out the ehcache config for exactly how to configure your cache.

If your aggregate has at most 5 events, you might not need either cache nor snapshotter. Loading the aggregate from 4 events will not give you a tremendous latency. If all 5 events happen in a very short amount of time, you could consider using a cache for improved performance or latency reduction.

Cheers,

Allard

Thanks Allard, I will play with your input later tonight:)

Hi

Is there any way to use hazelcast for cache in CachingEventSourcingRepository?

Thanks
Deepak

Hi,

I’m running an Axon 3 based app on production with Hazelcast as an aggregate cache + I use Hazelcast distributed locks for locking the aggregate - this way I can run multiple instances of the same Axon app without dealing with distributed command bus at all.

Let me know if you need any help or code snippets regarding the use of Hazelcast.

Szymon

W dniu piątek, 6 października 2017 11:50:55 UTC+2 użytkownik Deepak Gupta napisał:

Hi Szymon,

From Axon Documentation, i came to know about jCache adapter. I am trying to use hazelcast as jcache cache provider. Still no luck yet. It would be great if you share the working code snippet or do the help.

Thanks
Deepak Gupta