Skip to content
This repository has been archived by the owner on Feb 9, 2019. It is now read-only.

added support for JedisSentinelPool #101

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions redis/project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ object MinimalBuild extends Build {
lazy val typesafe = "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
lazy val repo = if (buildVersion.endsWith("SNAPSHOT")) typesafeSnapshot else typesafe
lazy val pk11 = "pk11 repo" at "http://pk11-scratch.googlecode.com/svn/trunk"
// for jedis-2.2.2-SNAPSHOT which sedis 1.2.0 depends on
lazy val sonatype = "sonatype repo" at "http://oss.sonatype.org/content/groups/public"
lazy val root = Project(id = "play-plugins-redis", base = file("."), settings = Project.defaultSettings).settings(
version := "2.2.0",
version := "2.2.1-SNAPSHOT",
scalaVersion := "2.10.2",
//publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/.m2/repository"))),
publishTo <<= (version) { version: String =>
val nexus = "https://private-repo.typesafe.com/typesafe/"
if (version.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "maven-snapshots/")
Expand All @@ -20,10 +23,11 @@ object MinimalBuild extends Build {
organization := "com.typesafe",
resolvers += repo,
resolvers += pk11,
resolvers += sonatype,
javacOptions += "-Xlint:unchecked",
libraryDependencies += "biz.source_code" % "base64coder" % "2010-12-19",
libraryDependencies += "com.typesafe" %% "play-plugins-util" % buildVersion,
libraryDependencies += "com.typesafe.play" %% "play-cache" % buildVersion % "provided",
libraryDependencies += "org.sedis" % "sedis_2.10.0" % "1.1.1"
libraryDependencies += "org.sedis" % "sedis_2.10.0" % "1.2.0"
)
}
2 changes: 2 additions & 0 deletions redis/sample/app/Global.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class Global extends GlobalSettings {

public void onStart(Application app) {
JedisPool p = app.plugin(RedisPlugin.class).jedisPool();
// uncomment to test sentinel setup
//JedisSentinelPool p = app.plugin(RedisPlugin.class).jedisSentinelPool();
Jedis j = p.getResource();
j.set("foo","yay");
p.returnResource(j);
Expand Down
2 changes: 2 additions & 0 deletions redis/sample/app/controllers/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class Application extends Controller {

public static Result index() {
JedisPool p = Play.application().plugin(RedisPlugin.class).jedisPool();
// uncomment to test sentinel setup
//JedisSentinelPool p = Play.application().plugin(RedisPlugin.class).jedisSentinelPool();
Jedis j = p.getResource();
String r = j.get("foo") + " - foo2:" + j.get("foo2");
p.returnResource(j);
Expand Down
6 changes: 6 additions & 0 deletions redis/sample/conf/application.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# This is the main configuration file for the application.
# ~~~~~

# enable to test sentinel setup
redis.sentinel.mode=false
redis.sentinel.hosts=["localhost:26379", "localhost:26380"]
redis.master.name=mymaster
#redis.key.prefix=AppName

# Secret key
# ~~~~~
# The secret key is used to secure cryptographics functions.
Expand Down
2 changes: 1 addition & 1 deletion redis/sample/project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object ApplicationBuild extends Build {
val appVersion = "1.0-SNAPSHOT"

val appDependencies = Seq(
"com.typesafe" %% "play-plugins-redis" % "2.2.0",
"com.typesafe" %% "play-plugins-redis" % "2.2.1-SNAPSHOT",
"com.typesafe.play" %% "play-cache" % "2.2.0"
)

Expand Down
114 changes: 85 additions & 29 deletions redis/src/main/scala/com/typesafe/plugin/RedisPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import play.api._
import org.sedis._
import redis.clients.jedis._
import play.api.cache._
import java.util._
import java.io._
import java.net.URI
import biz.source_code.base64Coder._
import org.apache.commons.lang3.builder._
import org.apache.commons.pool.impl.GenericObjectPool
import play.api.mvc.Result
import scala.collection.JavaConversions._

/**
* provides a redis client and a CachePlugin implementation
Expand All @@ -37,6 +36,17 @@ class RedisPlugin(app: Application) extends CachePlugin {
private lazy val timeout = app.configuration.getInt("redis.timeout")
.getOrElse(2000)

private lazy val sentinelMode = app.configuration.getBoolean("redis.sentinel.mode")
.getOrElse(false)

private lazy val sentinelHosts : java.util.List[String] = app.configuration.getStringList("redis.sentinel.hosts")
.getOrElse(seqAsJavaList(List("localhost:26379")))

private lazy val masterName = app.configuration.getString("redis.master.name")
.getOrElse("mymaster")

private lazy val keyPrefix = app.configuration.getString("redis.key.prefix")
.getOrElse("")

/**
* provides access to the underlying jedis Pool
Expand All @@ -53,36 +63,54 @@ class RedisPlugin(app: Application) extends CachePlugin {
*/
lazy val sedisPool = new Pool(jedisPool)

/**
* provides access to the underlying jedis sentinel Pool
*/
lazy val jedisSentinelPool = {
val poolConfig = createPoolConfig(app)
Logger.info(s"Redis Plugin enabled. Connecting to Redis sentinels ${sentinelHosts} with timeout ${timeout}.")
Logger.info("Redis Plugin pool configuration: " + new ReflectionToStringBuilder(poolConfig).toString())
val sentinelSet = new java.util.HashSet[String]()
sentinelSet.addAll(sentinelHosts)
new JedisSentinelPool(masterName, sentinelSet, poolConfig, timeout, password)
}

/**
* provides access to the sedis sentinel Pool
*/
lazy val sedisSentinelPool = new SentinelPool(jedisSentinelPool)

private def createPoolConfig(app: Application) : JedisPoolConfig = {
val poolConfig : JedisPoolConfig = new JedisPoolConfig()
app.configuration.getInt("redis.pool.maxIdle").map { poolConfig.maxIdle = _ }
app.configuration.getInt("redis.pool.minIdle").map { poolConfig.minIdle = _ }
app.configuration.getInt("redis.pool.maxActive").map { poolConfig.maxActive = _ }
app.configuration.getInt("redis.pool.maxWait").map { poolConfig.maxWait = _ }
app.configuration.getBoolean("redis.pool.testOnBorrow").map { poolConfig.testOnBorrow = _ }
app.configuration.getBoolean("redis.pool.testOnReturn").map { poolConfig.testOnReturn = _ }
app.configuration.getBoolean("redis.pool.testWhileIdle").map { poolConfig.testWhileIdle = _ }
app.configuration.getLong("redis.pool.timeBetweenEvictionRunsMillis").map { poolConfig.timeBetweenEvictionRunsMillis = _ }
app.configuration.getInt("redis.pool.numTestsPerEvictionRun").map { poolConfig.numTestsPerEvictionRun = _ }
app.configuration.getLong("redis.pool.minEvictableIdleTimeMillis").map { poolConfig.minEvictableIdleTimeMillis = _ }
app.configuration.getLong("redis.pool.softMinEvictableIdleTimeMillis").map { poolConfig.softMinEvictableIdleTimeMillis = _ }
app.configuration.getBoolean("redis.pool.lifo").map { poolConfig.lifo = _ }
app.configuration.getString("redis.pool.whenExhaustedAction").map { setting =>
poolConfig.whenExhaustedAction = setting match {
case "fail" | "0" => GenericObjectPool.WHEN_EXHAUSTED_FAIL
case "block" | "1" => GenericObjectPool.WHEN_EXHAUSTED_BLOCK
case "grow" | "2" => GenericObjectPool.WHEN_EXHAUSTED_FAIL
}
}
app.configuration.getInt("redis.pool.maxIdle").map { poolConfig.setMaxIdle(_) }
app.configuration.getInt("redis.pool.minIdle").map { poolConfig.setMinIdle(_) }
app.configuration.getInt("redis.pool.maxTotal").map { poolConfig.setMaxTotal(_) }
app.configuration.getBoolean("redis.pool.testOnBorrow").map { poolConfig.setTestOnBorrow(_) }
app.configuration.getBoolean("redis.pool.testOnReturn").map { poolConfig.setTestOnReturn(_) }
app.configuration.getBoolean("redis.pool.testWhileIdle").map { poolConfig.setTestWhileIdle(_) }
app.configuration.getLong("redis.pool.timeBetweenEvictionRunsMillis").map { poolConfig.setTimeBetweenEvictionRunsMillis(_) }
app.configuration.getInt("redis.pool.numTestsPerEvictionRun").map { poolConfig.setNumTestsPerEvictionRun(_) }
app.configuration.getLong("redis.pool.minEvictableIdleTimeMillis").map { poolConfig.setMinEvictableIdleTimeMillis(_) }
app.configuration.getLong("redis.pool.softMinEvictableIdleTimeMillis").map { poolConfig.setSoftMinEvictableIdleTimeMillis(_) }
app.configuration.getBoolean("redis.pool.lifo").map { poolConfig.setLifo(_) }
app.configuration.getBoolean("redis.pool.blockWhenExhausted").map { poolConfig.setBlockWhenExhausted(_) }
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new version of jedis now depends on commons pool 2

poolConfig
}

override def onStart() {
sedisPool
if (sentinelMode) {
sedisSentinelPool
} else {
sedisPool
}
}

override def onStop() {
jedisPool.destroy()
if (sentinelMode) {
jedisSentinelPool.destroy()
} else {
jedisPool.destroy()
}
}

override lazy val enabled = {
Expand All @@ -97,6 +125,11 @@ class RedisPlugin(app: Application) extends CachePlugin {
lazy val api = new CacheAPI {

def set(key: String, value: Any, expiration: Int) {
if (value == null) {
Logger.warn("not setting key:"+ key + " because value is null")
return
}

var oos: ObjectOutputStream = null
var dos: DataOutputStream = null
try {
Expand Down Expand Up @@ -132,10 +165,11 @@ class RedisPlugin(app: Application) extends CachePlugin {
}
val redisV = prefix + "-" + new String( Base64Coder.encode( baos.toByteArray() ) )
Logger.trace(s"Setting key ${key} to ${redisV}")

sedisPool.withJedisClient { client =>
client.set(key,redisV)
if (expiration != 0) client.expire(key,expiration)

if (sentinelMode) {
sedisSentinelPool.withJedisClient { client => setValue(client, key, redisV, expiration) }
} else {
sedisPool.withJedisClient { client => setValue(client, key, redisV, expiration) }
}
} catch {case ex: IOException =>
Logger.warn("could not serialize key:"+ key + " and value:"+ value.toString + " ex:"+ex.toString)
Expand All @@ -145,7 +179,23 @@ class RedisPlugin(app: Application) extends CachePlugin {
}

}
def remove(key: String): Unit = sedisPool.withJedisClient { client => client.del(key) }

private def getFullKey(key: String): String = {
if (keyPrefix.length > 0) keyPrefix + ":" + key else key
}

private def setValue(client: Jedis, key: String, value: String, expiration: Int) {
client.set(getFullKey(key), value)
if (expiration != 0) client.expire(getFullKey(key), expiration)
}

def remove(key: String): Unit = {
if (sentinelMode) {
sedisSentinelPool.withJedisClient { client => client.del(getFullKey(key)) }
} else {
sedisPool.withJedisClient { client => client.del(getFullKey(key)) }
}
}

class ClassLoaderObjectInputStream(stream:InputStream) extends ObjectInputStream(stream) {
override protected def resolveClass(desc: ObjectStreamClass) = {
Expand All @@ -159,7 +209,13 @@ class RedisPlugin(app: Application) extends CachePlugin {
var ois: ObjectInputStream = null
var dis: DataInputStream = null
try {
val rawData = sedisPool.withJedisClient { client => client.get(key) }
val rawData = {
if (sentinelMode) {
sedisSentinelPool.withJedisClient { client => client.get(getFullKey(key)) }
} else {
sedisPool.withJedisClient { client => client.get(getFullKey(key)) }
}
}
rawData match {
case null =>
None
Expand Down