Redis Transactional
A Redis transactional projection is a transactional projection based on Redisson RTransaction.
Compared to a Spring transactional projection, a Redis transactional projection is more lightweight since
- transactionality is directly provided by
RTransaction
. There is no need to deal with Spring’sPlatformTransactionManager
- the fact stream position is automatically managed (see example below)
Motivation
You would want to use Redis Transactional for two reasons:
- atomicity of factStreamPosition updates and your projection state updates
- increased fact processing throughput
The performance bit is achieved by skipping unnecessary factStreamPosition updates and (more importantly) by
reducing the number of operations on your Redis backend by using bulkSize
updates with one redisson transsaction
instead of single writes.
The bulkSize
is configurable per projection via the @RedisTransactional
annotation.
Working with a Redis transactional projection you can read your own uncommitted write. For this reason, a Redis transactional projection is best used for projections which need to access the projection’s data during the handling of an event.
If this is not necessary, you could also use a better performing alternative: Redis batch projection
Configuration
In order to make use of redisson RTransaction support, the necessary dependency has to be included in your project:
<dependency>
<groupId>org.factcast</groupId>
<artifactId>factcast-factus-redis</artifactId>
</dependency>
Structure
A Redis transactional projection can be a managed- or a subscribed projection and is defined as follows:
- it is annotated with
@RedisTransactional
- it implements
RedisProjection
revealing theRedisClient
used - it provides the serial number of the projection via the
@ProjectionMetaData
annotation - the handler methods receive an additional
RTransaction
parameter
Note
Factus provides convenient abstract classes for managed and subscribed projections:
AbstractRedisManagedProjection
AbstractRedisSubscribedProjection
Example
@Handler
void apply(SomethingHappened fact, RTransaction tx) {
myMap = tx.getMap( ... ).put( fact.getKey() , fact.getValue() );
}
a full example can be found here