Note: This version supports Play framework 2.5.x with JDK 8.
For previous versions see older releases.
By default, Play framework 2 is delivered with EHCache module implementing
CacheApi.
This module enables use of the redis-server, i.e., key/value cache, within the
Play framework 2. Besides the backward compatibility with the CacheApi,
it introduces more evolved API providing various handful operations. Besides the basic methods such as
get
, set
and remove
, it provides more convenient methods such as expire
, exists
, invalidate
and much more.
As the cache implementation uses Akka actor system, it is completely non-blocking and asynchronous.
Furthermore, we deliver the library with several configuration providers to let you easily use
play-redis on Heroku as well as on your premise.
This library delivers a single module with following implementations of the API. While the core of the framework is fully non-blocking, most of provided facades are blocking wrappers.
play.api.cache.redis.CacheApi
(blocking Scala implementation)play.api.cache.redis.CacheAsyncApi
(non-blocking Scala implementation)play.api.cache.CacheApi
(Play's blocking API for Scala)play.cache.CacheApi
(Play's blocking API for Java)
First, the CacheApi
is extended play.api.cache.CacheApi
and it implements the connection in the blocking manner.
Second, the CacheAsyncApi
enables non-blocking connection providing results through scala.concurrent.Future
.
Third, the synchronous implementation also implements standard CacheApi
bundled within Play framework. Finally,
the play.cache.CacheApi
is implementation of standard CacheApi
for Java.
This module builds over Brando connector and is intended only for Scala version of the Play framework.
To your SBT build.sbt
add the following lines:
// redis-server cache
libraryDependencies += "com.github.karelcemus" %% "play-redis" % "1.2.0"
// repository with the Brando connector
resolvers += "Brando Repository" at "http://chrisdinn.github.io/releases/"
Now we must enable our redis cache module and disable default Play's EhCache module. Into application.conf
and following
two lines:
# disable default Play framework cache plugin
play.modules.disabled += "play.api.cache.EhCacheModule"
# enable redis cache module
play.modules.enabled += "play.api.cache.redis.RedisCacheModule"
When you have the library added to your project, you can safely inject the play.api.cache.redis.CacheApi
trait
for the synchronous cache. If you want the asynchronous implementation, then inject play.api.cache.redis.CacheAsyncApi
.
There might be some limitations with data types but it should not be anything major. (Note: it uses Akka serialization.
Supported data types are primitives, objects serializable through the java serialization and collections.)
If you encounter any issue, please feel free to report it.
Example:
import scala.concurrent.Future
import scala.concurrent.duration._
import play.api.cache.redis.CacheApi
class MyController @Inject() ( cache: CacheApi ) {
cache.set( "key", "value" )
// returns Option[ T ] where T stands for String in this example
cache.get[ String ]( "key" )
cache.remove( "key" )
cache.set( "object", MyCaseClass() )
// returns Option[ T ] where T stands for MyCaseClass
cache.get[ MyCaseClass ]( "object" )
// returns Unit
cache.set( "key", 1.23 )
// returns Option[ Double ]
cache.get[ Double ]( "key" )
// returns Option[ MyCaseClass ]
cache.get[ MyCaseClass ]( "object" )
// returns T where T is Double. If the value is not in the cache
// the computed result is saved
cache.getOrElse( "key" )( 1.24 )
// same as getOrElse but works for Futures. It returns Future[ T ]
cache.getOrFuture( "key" )( Future( 1.24 ) )
// returns Unit and removes a key/keys from the storage
cache.remove( "key" )
cache.remove( "key1", "key2" )
cache.remove( "key1", "key2", "key3" )
// remove all expects a sequence of keys, it performs same be behavior
// as remove methods, they are just syntax sugar
cache.removeAll( "key1", "key2", "key3" )
// removes all keys in the redis database! Beware using it
cache.invalidate()
// refreshes expiration of the key if present
cache.expire( "key", 1.second )
// returns true if the key is in the storage, false otherwise
cache.exists( "key" )
// returns all keys matching given pattern. Beware, complexity is O(n),
// where n is the size of the database. It executes KEYS command.
cache.matching( "page/1/*" )
// removes all keys matching given pattern. Beware, complexity is O(n),
// where n is the size of the database. It internally uses method matching.
// It executes KEYS and DEL commands in a transaction.
cache.removeMatching( "page/1/*" )
// importing `play.api.cache.redis._` enables us
// using both `java.util.Date` and `org.joda.time.DateTime` as expiration
// dates instead of duration. These implicits are useful when
// we know the data regularly changes, e.g., at midnight, at 3 AM, etc.
// We do not have compute the duration ourselves, the library
// can do it for us
import play.api.cache.redis._
cache.set( "key", "value", DateTime.parse( "2015-12-01T00:00" ).asExpiration )
}
Regardless of current API, all operations throw an exception when fail. Consequently,
successful invocations do not throw an exception. The only difference is in checking for errors.
While synchronous APIs really throw an exception, asynchronous API returns a Future
wrapping both the success and the exception, i.e., use onFailure
or onComplete
to
check for errors.
There is already default configuration but it can be overwritten in your conf/application.conf
file.
Key | Type | Default | Description |
---|---|---|---|
play.cache.redis.host | String | localhost |
redis-server address |
play.cache.redis.port | Int | 6379 |
redis-server port |
play.cache.redis.database | Int | 1 |
redis-server database, 1-15 |
play.cache.redis.timeout | Duration | 1s |
connection timeout |
play.cache.redis.dispatcher | String | akka.actor.default-dispatcher |
Akka actor |
play.cache.redis.configuration | String | static |
Defines which configuration source enable. Accepted values are static , env , custom |
play.cache.redis.password | String | null |
When authentication is required, this is the password. Value is optional. |
play.cache.redis.connection-string-variable | String | REDIS_URL |
Name of the environment variable with the connection string. This is used in combination with the env configuration. This allows customization of the variable name in PaaS environment. Value is optional. |
In various environments there are various sources of the connection string defining how to connect to Redis instance.
For example, at localhost we are interested in direct definition of host and port in the application.conf
file.
However, this approach does not fit all environments. For example, Heroku supplies REDIS_URL
environment variable
defining the connection string. To resolve this diversity, the library expects an implementation of the Configuration
trait available through DI. By default, it enables static
configuration source, i.e., it reads the settings from the
static configuration file. Another supplied configuration reader is env
, which reads the environment variable such as
REDIS_URL
but the name is configurable. To disable built-in providers you are free to set custom
and supply your
own implementation of the Configuration
trait.
To enable redis cache on Heroku we have to do the following steps:
- add library into application dependencies
- enable
RedisCacheModule
- disable
EhCacheModule
- set
play.cache.redis.configuration: env
- done, we can run it and use any of 3 provided interfaces
However, there are scenarios when we need to customize the configuration to better fit our needs. Usually, we might encounter this when we have a specific development flow or use a specific PaaS. To enable redis cache implementation with customized configuration we have to do the following steps:
- add library into application dependencies
- enable
RedisCacheModule
- disable
EhCacheModule
- set
play.cache.redis.configuration: custom
- Implement
play.api.cache.redis.Configuration
trait - Register the implementation into DI provider. This is specific for each provider. If you are using Guice, which is Play's default DI provider, then look here. It gives you a hint how to register the implementation during application start.
- done, we can run it and use any of 3 provided interfaces
The library does not enable the redis module by default. It is to avoid conflict with Play's default EhCache. The Play discourages disabling modules within the library thus it leaves it up to developers to disable EhCache and enable Redis manually. This also allows you to use EhCache in your dev environment and redis in production. Nevertheless, this module replaces the EHCache and it is not intended to use both implementations along.
play framework | play-redis |
---|---|
2.5.x | 1.2.0 |
2.4.x | 1.0.0 |
2.3.x | 0.2.1 |
Play-redis provides native serialization support to basic data types such as String, Int, etc.
However, for other objects including collections, it used to use default JavaSerializer
serializer.
Since Akka 2.4.1, default JavaSerializer
is officially considered inefficient for production use.
Nevertheless, to keep things simple, play-redis still uses this inefficient serializer NOT to enforce any serialization
library to end users. Although, it recommends kryo serializer claiming
great performance and small output stream. Any serialization library can be smoothly connected through Akka
configuration, see the official Akka documentation.
This release is focused on library refactoring. While public API remained unchanged, there are several significant
changes to their implementations. Those are consequences of refactoring some functionality into self-standing
units. For example, there has been extracted RedisConnector
implementing the Redis protocol
and RedisCache
implementing cache API over that. Before, it was tangled together. As consequence, the library has
now layered architecture (facades -> cache implementation -> protocol implementation) with several public facades.
Update to Play 2.5, no significant changes
Redesigned the library from scratch to support Play 2.4.x API and use DI.