Git Product home page Git Product logo

rediscala's Introduction

rediscala Build Status Coverage Status Maven Central

A Redis client for Scala with non-blocking and asynchronous I/O operations.

  • Reactive : Redis requests/replies are wrapped in Futures.

  • Typesafe : Redis types are mapped to Scala types.

  • Fast : Rediscala uses redis pipelining. Blocking redis commands are moved into their own connection. A worker actor handles I/O operations (I/O bounds), another handles decoding of Redis replies (CPU bounds).

Set up your project dependencies

If you use SBT, you just have to edit build.sbt and add the following:

From version 1.9.0:

  • use akka 2.5.23 (java 1.8)
  • released for scala
    • 2.11
    • 2.12
    • 2.13
libraryDependencies += "com.github.etaty" %% "rediscala" % "1.9.0"

From version 1.8.0:

  • use akka 2.4.12 (java 1.8)
  • released for scala 2.11 & 2.12
libraryDependencies += "com.github.etaty" %% "rediscala" % "1.8.0"

From version 1.3.1:

  • use akka 2.3
  • released for scala 2.10 & 2.11
// new repo on maven.org
libraryDependencies += "com.github.etaty" %% "rediscala" % "1.7.0"


// old repo on bintray (1.5.0 and inferior version)
resolvers += "rediscala" at "http://dl.bintray.com/etaty/maven"
libraryDependencies += "com.etaty.rediscala" %% "rediscala" % "1.5.0"

For older rediscala versions (<= 1.3):

  • use akka 2.2
  • released for scala 2.10 only
  • use github "repo"
resolvers += "rediscala" at "https://raw.github.com/etaty/rediscala-mvn/master/releases/"

libraryDependencies += "com.etaty.rediscala" %% "rediscala" % "1.3"

Connect to the database

import redis.RedisClient
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object Main extends App {
  implicit val akkaSystem = akka.actor.ActorSystem()

  val redis = RedisClient()

  val futurePong = redis.ping()
  println("Ping sent!")
  futurePong.map(pong => {
    println(s"Redis replied with a $pong")
  })
  Await.result(futurePong, 5 seconds)

  akkaSystem.shutdown()
}

Basic Example

https://github.com/etaty/rediscala-demo

You can fork with : git clone [email protected]:etaty/rediscala-demo.git then run it, with sbt run

Redis Commands

All commands are supported :

Blocking commands

RedisBlockingClient is the instance allowing access to blocking commands :

  • blpop
  • brpop
  • brpopplush
  redisBlocking.blpop(Seq("workList", "otherKeyWithWork"), 5 seconds).map(result => {
    result.map({
      case (key, work) => println(s"list $key has work : ${work.utf8String}")
    })
  })

Full example: ExampleRediscalaBlocking

You can fork with: git clone [email protected]:etaty/rediscala-demo.git then run it, with sbt run

Transactions

The idea behind transactions in Rediscala is to start a transaction outside of a redis connection. We use the TransactionBuilder to store call to redis commands (and for each command we give back a future). When exec is called, TransactionBuilder will build and send all the commands together to the server. Then the futures will be completed. By doing that we can use a normal connection with pipelining, and avoiding to trap a command from outside, in the transaction...

  val redisTransaction = redis.transaction() // new TransactionBuilder
  redisTransaction.watch("key")
  val set = redisTransaction.set("key", "abcValue")
  val decr = redisTransaction.decr("key")
  val get = redisTransaction.get("key")
  redisTransaction.exec()

Full example: ExampleTransaction

You can fork with : git clone [email protected]:etaty/rediscala-demo.git then run it, with sbt run

TransactionsSpec will reveal even more gems of the API.

Pub/Sub

You can use a case class with callbacks RedisPubSub or extend the actor RedisSubscriberActor as shown in the example below

object ExamplePubSub extends App {
  implicit val akkaSystem = akka.actor.ActorSystem()

  val redis = RedisClient()

  // publish after 2 seconds every 2 or 5 seconds
  akkaSystem.scheduler.schedule(2 seconds, 2 seconds)(redis.publish("time", System.currentTimeMillis()))
  akkaSystem.scheduler.schedule(2 seconds, 5 seconds)(redis.publish("pattern.match", "pattern value"))
  // shutdown Akka in 20 seconds
  akkaSystem.scheduler.scheduleOnce(20 seconds)(akkaSystem.shutdown())

  val channels = Seq("time")
  val patterns = Seq("pattern.*")
  // create SubscribeActor instance
  akkaSystem.actorOf(Props(classOf[SubscribeActor], channels, patterns).withDispatcher("rediscala.rediscala-client-worker-dispatcher"))

}

class SubscribeActor(channels: Seq[String] = Nil, patterns: Seq[String] = Nil) extends RedisSubscriberActor(channels, patterns) {
  override val address: InetSocketAddress = new InetSocketAddress("localhost", 6379)

  def onMessage(message: Message) {
    println(s"message received: $message")
  }

  def onPMessage(pmessage: PMessage) {
    println(s"pattern message received: $pmessage")
  }
}

Full example: ExamplePubSub

You can fork with : git clone [email protected]:etaty/rediscala-demo.git then run it, with sbt run

RedisPubSubSpec will reveal even more gems of the API.

Scripting

RedisScript is a helper, you can put your LUA script inside and it will compute the hash. You can use it with evalshaOrEval which run your script even if it wasn't already loaded.

  val redis = RedisClient()

  val redisScript = RedisScript("return 'rediscala'")

  val r = redis.evalshaOrEval(redisScript).map({
    case b: Bulk => println(b.toString())
  })
  Await.result(r, 5 seconds)

Full example: ExampleScripting

Redis Sentinel

SentinelClient connect to a redis sentinel server.

SentinelMonitoredRedisClient connect to a sentinel server to find the master addresse then start a connection. In case the master change your RedisClient connection will automatically connect to the new master server. If you are using a blocking client, you can use SentinelMonitoredRedisBlockingClient

Pool

RedisClientPool connect to a pool of redis servers. Redis commands are dispatched to redis connection in a round robin way.

Master Slave

RedisClientMasterSlaves connect to a master and a pool of slaves. The write commands are sent to the master, while the read commands are sent to the slaves in the RedisClientPool

Config Which Dispatcher to Use

By default, the actors in this project will use the dispatcher rediscala.rediscala-client-worker-dispatcher. If you want to use another dispatcher, just config the implicit value of redisDispatcher:

implicit val redisDispatcher = RedisDispatcher("akka.actor.default-dispatcher")

ByteStringSerializer ByteStringDeserializer ByteStringFormatter

ByteStringSerializer

ByteStringDeserializer

ByteStringFormatter

case class DumbClass(s1: String, s2: String)

object DumbClass {
  implicit val byteStringFormatter = new ByteStringFormatter[DumbClass] {
    def serialize(data: DumbClass): ByteString = {
      //...
    }

    def deserialize(bs: ByteString): DumbClass = {
      //...
    }
  }
}
//...

  val dumb = DumbClass("s1", "s2")

  val r = for {
    set <- redis.set("dumbKey", dumb)
    getDumbOpt <- redis.get[DumbClass]("dumbKey")
  } yield {
    getDumbOpt.map(getDumb => {
      assert(getDumb == dumb)
      println(getDumb)
    })
  }

Full example: ExampleByteStringFormatter

Scaladoc

Rediscala scaladoc API (version 1.9)

Rediscala scaladoc API (version 1.8)

Rediscala scaladoc API (version 1.7)

Rediscala scaladoc API (version 1.6)

Rediscala scaladoc API (version 1.5)

Rediscala scaladoc API (version 1.4)

Rediscala scaladoc API (version 1.3)

Rediscala scaladoc API (version 1.2)

Rediscala scaladoc API (version 1.1)

Rediscala scaladoc API (version 1.0)

Performance

More than 250 000 requests/second

The hardware used is a macbook retina (Intel Core i7, 2.6 GHz, 4 cores, 8 threads, 8GB) running the sun/oracle jvm 1.6

You can run the bench with :

  1. clone the repo git clone [email protected]:etaty/rediscala.git
  2. run sbt bench:test
  3. open the bench report rediscala/tmp/report/index.html

rediscala's People

Contributors

123avi avatar actsasbuffoon avatar adrien-aubel avatar alexanderscott avatar analytically avatar btd avatar ddworak avatar drmontgomery avatar etaty avatar fehmicansaglam avatar gchudnov avatar hussachai avatar jtanner avatar karelcemus avatar mmagn avatar npeters avatar ryanlecompte avatar stanch avatar stsmedia avatar th0br0 avatar tovbinm avatar wb14123 avatar xiaohai2016 avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rediscala's Issues

I can't download rediscala from github repo in travis ci ?

I make hibernate-rediscala using rediscala.
I using rediscala github repo like this

resolvers += "rediscala" at "https://github.com/etaty/rediscala-mvn/raw/master/releases/"

libraryDependencies ++= Seq("com.etaty.rediscala" %% "rediscala" % "1.3")

compile and test is success in my local computer.
but travis ci fail by can't download rediscala (handshake error with github)

am i wrong?

Message order guarantee for channel publishing

Can rediscala guarantee correct message order when publishing to a Redis channel from multiple threads ? If using different RedisClient instances ? If using the same shared RedisClient and a lock for synchronization ?

workerIO: Address Changed

onAddressChanged ~> tcpWorker ! ConfirmedClose

onConnectionClosed ~> if current connection then reconnect

+add tests

Client pooling with Sentinel

Hi,

I am evaluating the options for a redis client.

I noticed that there is no example using sentinel that has been put up..

I would like to use sentinel and have client pooling as well.

Is it possible?

Any tips would be useful!

In the UI I do not see how to label this as a question. Neither do I see any other way to communicate with the authors.

Client timeouts on non-blocking ops to redis server?

Hi,

I'm curious how this client supports timeouts on non blocking ops to the redis server. For example, if the redis server is being extremely extremely slow, what is the behavior, and when will the client timeout?

Thanks

question about queue-like behavior using rediscala

Hello,
I deployed your rediscala client in Akka microkernel and I tested pub/sub functionality, which worked great.
I was wondering if it was possible to achieve queue behavior using rediscala? So that once subscriber actor consumed the message no other actor would get it?
Cheers,

Marcin

KeySpace based notified events not being captured

I am attempting to set a keyspace notification for regex key pattern on HM* events
The publisher in this case will be redis keyspace notifier

Step1:

Modify redis.conf to support keyspace notification

Add Line
notify-keyspace-events KEhx

(Refer http://redis.io/topics/notifications)

Step2:

Restart Redis with revised conf - "./src/redis-server redis.conf"

Step3

Create Subscriber using PubSub example indicated in redisscala

class SubscribeActor(channels: Seq[String] = Nil, patterns: Seq[String] = Nil)
extends RedisSubscriberActor(new InetSocketAddress("localhost", 6379), channels, patterns) {

def onMessage(message: Message) {
println(s" message received: $message")
}

def onPMessage(pmessage: PMessage) {
println(s"pattern message received: $pmessage")
}
}

implicit val akkaSystem = akka.actor.ActorSystem()

val redis = RedisClient()

// Pattern is keyspace@0:foo.*

val channels = Seq("keyspace@0:foo.*")
val patterns = Nil
akkaSystem.actorOf(Props(classOf[SubscribeActor], channels, patterns).withDispatcher("rediscala.rediscala-client-worker-dispatcher"))

Step4

Using Redis CLI, initiate an HMSET operation

127.0.0.1:6379> HMSET foo.x f1 "a" f2 "b"

I am not receiving or noticing event capture in the scalaredis subscriber console.

If I set up a subscription via redis-cli , I am able to see the notification captured as expected

redis 127.0.0.1:6379> psubscribe 'key*:foo_'
Reading messages... (press Ctrl-C to quit)

  1. "psubscribe"
  2. "key**:foo"
  3. (integer) 1
  4. "pmessage"
  5. "_key**:foo*"
  6. "keyspace@0:foobi"
  7. "hset"

Am I missing anything?

How to run included benchmarks?

I ran sbt bench:test which looks like it runs a bunch of tests, but there's no html output with the performance results. I then tried uncommenting out the benchTestSettings in the buildfile, and got a bunch of compilation errors. Is there a simple way to run the benchmarks? Thanks

Missing documentation on ByteStringSerializer parameters

What are these parameters used for?

example:

def zrevrank[V: ByteStringSerializer](key: String, member: V): Future[Option[Long]]
def zrank[V: ByteStringSerializer](key: String, member: V): Future[Option[Long]]

What is expected to be used as the value for member?

brpop, blpop operation need isMasterOnly = true

I ran brpop, blpop operation to Slave Client, occur not use in Readonly server.

but brpop, blpop not setting "isMasterOnly = true"

In Master-Slave env, connect to slave server, and send blpop, brpop
READONLY *************

sha1 checksum mismatch for rediscala_2.11-1.4.0.jar

when download libs via sbt update, it shows:
[warn] [FAILED ] com.etaty.rediscala#rediscala_2.11;1.4.0!rediscala_2.11.jar: invalid sha1: expected=f7a7af8d640426897704864c91e267e6768e24a2 computed=8543f4b8b18a83884b5b0749c0f0db93f30eac96 (17812ms)

whatever it's downloaded from repo.typesafe.com or dl.bintray.com

Why is there no ByteString => T deserializer?

I can do redis.set("key", MyCustomType(42)) as long as I have a valid RedisValueConverter in implicit scope for my custom type.

But when I do redis.get("key") all I get is a raw Option[ByteString] and I have to convert it back to my custom type myself.

Why is there not a get[T: RedisValueDeserializer](key: String): Future[Option[T]] with some basic support for common types (Strings, Ints, Longs, Booleans, Lists, Sets, Maps, etc.)? Then I can have my own RedisValueDeserializer in scope to deserialize my custom types.

Exception in RedisReplyDecoder after reconnection

If connection to Redis was lost and then reestablished sometimes there are unhandled exceptions in all instances of RedisReplyDecoder at once:

20:57:11.004 [kka.actor.default-dispatcher-2] ERROR akka.actor.OneForOneStrategy - rediscala.rediscala-client-worker-dispatcher-90:akka://****/user/****-client-$G/$l - null
java.util.NoSuchElementException: null
    at scala.collection.mutable.MutableList.head(MutableList.scala:54) ~[scala-library-2.10.2.jar:na]
    at scala.collection.mutable.Queue.front(Queue.scala:168) ~[scala-library-2.10.2.jar:na]
    at redis.actors.RedisReplyDecoder.decodeRepliesRecur(RedisReplyDecoder.scala:47) ~[rediscala_2.10-1.1.jar:1.1]
    at redis.actors.RedisReplyDecoder.decodeReplies(RedisReplyDecoder.scala:42) ~[rediscala_2.10-1.1.jar:1.1]
    at redis.actors.RedisReplyDecoder$$anonfun$receive$1.applyOrElse(RedisReplyDecoder.scala:29) ~[rediscala_2.10-1.1.jar:1.1]
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498) ~[akka-actor_2.10-2.2.1.jar:2.2.1]
    at akka.actor.ActorCell.invoke(ActorCell.scala:456) ~[akka-actor_2.10-2.2.1.jar:2.2.1]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237) ~[akka-actor_2.10-2.2.1.jar:2.2.1]
    at akka.dispatch.Mailbox.run(Mailbox.scala:219) ~[akka-actor_2.10-2.2.1.jar:2.2.1]
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386) ~[akka-actor_2.10-2.2.1.jar:2.2.1]
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) ~[scala-library-2.10.2.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) ~[scala-library-2.10.2.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) ~[scala-library-2.10.2.jar:na]
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) ~[scala-library-2.10.2.jar:na]

Add `Config` entity for configuring

Consider wrapping address: InetSocketAddress and reconnectDuration: FiniteDuration in a Config class. Should be useful in future when additional configuration parameters are required.

Add support for listening of connection state changes

In our project we use password-protected Redis instance for writing.

Right after RedisClient creation it is more or less trivial to AUTH to it (and SELECT if it is needed), but if connection was lost afterwards, Rediscala do not provide any useful info about reconnection and also do not store AUTH data in connector actor to authentificate itself automatically.

Thus if we want to re-authenticate ourselves we need to either check Future's failures for "ERR Operation not permitted" messages or parse logs.

I think it would be very useful to provide some form of callback or listener to connection state changes. Also, it could be useful (but not too secure) to store last used AUTH and SELECT data to auto exec them right after reconnection.

load tests and number of concurrent connections

Hi,

I'm trying to find the best way to use redis from a play framework application, to support a great number of connections and have a good request/second and response time ratio.

I made a few gatling tests : redisscala with async play features, redis-scala in blocking mode (with 'Await') and a bigger play thread pool, and finally Jedis/Sedis (synchronous and blocking).

My results are surprising : I reach the best scalability with the Jedis driver.
With Jedis I can easily reach 500 connected users (500 threads) but with redisscala if I use more than 100 threads to stress the app, it becomes very slow.

My code is very simple :

def asyncRedisQuery(q: String) = Action.async {
    val redis = RedisClient()
    redis.get(q).map(_.get).map(_.utf8String).map( result =>   
        Ok(result)
      )
  }

N.B : I've tried several execution context and thread pool configuration.

Did I miss something?

Thanks

Sub Message data type

Hi.

I am trying to use RedisPubSub and noticed that Message case class have data String, which is strange (and encode it to utf8). It looks more sense will be if it will be ByteString because message is just bytes (and i cannot use now java serialization to decode case classes).
Or maybe i miss something - how can i use data String to deserialize case class?

Transaction is not working as expected

Th following Transaction will never commit, promises deadlock! That 's absolutely not acceptable.

object ExampleTransaction extends App {
  implicit val akkaSystem = akka.actor.ActorSystem()
  val redis = RedisClient("192.168.0.8", 6379)

  var keyX = "x"
  var keyY = "y"
  var keySum = "sum"
  //init values of x and y
  var setX = redis.set(keyX, 101)
  var setY = redis.set(keyY, 103)

  for {
     setXStatus <- setX
     setYStatus <- setY
  } yield {
    assert(setXStatus)
    assert(setYStatus)

    val redisTransaction = redis.transaction()
    redisTransaction.watch(keyX)
    redisTransaction.watch(keyY)
    var keyXFuture = redisTransaction.get(keyX);
    var keyYFuture = redisTransaction.get(keyY);
    var r = for {
        x <- keyXFuture
        y <- keyYFuture
    } yield {
        var sum = ParseNumber.parseInt(x.getOrElse(ByteString("-1"))) + ParseNumber.parseInt(y.getOrElse(ByteString("-1")))
        println("set(sum, x + y)|(x+y)=" + sum)
        redisTransaction.set(keySum, sum)
        redisTransaction.exec()
    }
     Await.result(r, 10 seconds)
  }

  Thread.sleep(1000*10)
  akkaSystem.shutdown()
}

Th following Transaction should not commit since watched keys has been changed. But it commit normally. That 's absolutely not acceptable.

object ExampleTransaction extends App {
  implicit val akkaSystem = akka.actor.ActorSystem()
  val redis = RedisClient("192.168.0.8", 6379)
  val anotherRedis = RedisClient("192.168.0.8", 6379)

  var keyX = "x"
  var keyY = "y"
  var keySum = "sum"
  //init value of x and y
  var setX = redis.set(keyX, 101)
  var setY = redis.set(keyY, 103)

  for {
     setXStatus <- setX
     setYStatus <- setY
  } yield {
    assert(setXStatus)
    assert(setYStatus)

    val redisTransaction = redis.transaction()
    redisTransaction.watch(keyX)
    redisTransaction.watch(keyY)
    var keyXFuture = redis.get(keyX);
    var keyYFuture = redis.get(keyY);

    //x and y modified by anotherRedis client
    anotherRedis.set(keyX, -101)
    anotherRedis.set(keyY, -103)
    Thread.sleep(1000)

    var r = for {
        x <- keyXFuture
        y <- keyYFuture
    } yield {
        var sum = ParseNumber.parseInt(x.getOrElse(ByteString("-1"))) + ParseNumber.parseInt(y.getOrElse(ByteString("-1")))
        println("set(sum, x + y)|(x+y)=" + sum)
        redisTransaction.set(keySum, sum)
        redisTransaction.exec()
    }

     Await.result(r, 10 seconds)
  }

  Thread.sleep(1000*10)
  akkaSystem.shutdown()
}

Hope that Transaction should be fully supported. I think Transaction should be implemented just like implemention of the blocking commands on the Lists.

Thanks & Best Regards!

Sort command need isMasterOnly = true

When sort key in Master-Slaves
I got error like this "READONLY You can't write against a read only slave."

need set isMasterOnly = true in Sort class

Decoding a zscore result of `inf` or `-inf` fails

I am using rediscala @ 1.4.2. If I add a member to a sorted set with positive or negative infinity as the score, running the zscore command for that member of the sorted set results in an exception due to parseDouble.

In the example below, we get inf and -inf as the resulting scores from redis.

$ redis-cli
127.0.0.1:6379> zadd test:zset Inf "test"
(integer) 1
127.0.0.1:6379> zscore test:zset "test"
"inf"
127.0.0.1:6379> zadd test:zset -Inf "test1"
(integer) 1
127.0.0.1:6379> zscore test:zset "test1"
"-inf"
127.0.0.1:6379> exit

However, java.lang.Double.parseDouble expects Infinity or -Infinity. Also below is an example trying to parse inf.

$ scala
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_31).
Type in expressions to have them evaluated.
Type :help for more information.

scala> Double.PositiveInfinity
res0: Double = Infinity

scala> Double.PositiveInfinity.toString
res1: String = Infinity

scala> java.lang.Double.parseDouble(res1)
res3: Double = Infinity

scala> Double.NegativeInfinity.toString
res4: String = -Infinity

scala> java.lang.Double.parseDouble(res4)
res5: Double = -Infinity

scala> java.lang.Double.parseDouble("inf")
java.lang.NumberFormatException: For input string: "inf"
  at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
  at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
  at java.lang.Double.parseDouble(Double.java:538)
  ... 33 elided

scala> :q

Scala-2.11 Support?

Is anyone working on a rediscala version that works with scala-2.11, sbt-0.13.2, akka-2.3.2?

Update Rediscala binaries to Akka 2.3.0 binaries

Current Rediscala 1.3 binaries somehow incompatible with Akka 2.3.0 binaries. During runtime following exception occurs:

java.lang.NoSuchMethodError: akka.actor.ActorSystem.dispatcher()Lscala/concurrent/ExecutionContext;
    at redis.RedisClientActorLike.<init>(Redis.scala:31)
    at redis.RedisClient.<init>(Redis.scala:69)

After repackaging of Rediscala with new Akka jar's problem disappears.

Sentinel onSentinelDown Issue

Hi

I've a problem with SentinelMonitoredRedisClient when one of my sentinel instance is down, the sentinelClient Instance is removed from sentinelClients list but the actor try to reconnect to sentinel each 2 seconds.

In case when one or more sentinel instances will stay down, i'll have multiple actors tryin to reconnect to non-existing sentinel instances.

after search, i find that redisscala schedule reconnect when connection is closed (class RedisWorkerIO)

I'd like to not have this behavior in case when i use sentinelClient.

Thanks

Extending on RedisSubscriberActor and overriding receive

I've tried to do the following with disastrously unpredictable behavior. It took a while to understand the problem was with overriding function receive. I would like to dynamically add and withdraw channels to a single subscriber instead of creating many subscribers and passing a final channel list to their constructor. Do you advise against this ? Do you have a suggestion on how to override receive properly to fit your design ?

case class RedisUuidSubscriberAdd(uuid: UUID)
case class RedisUuidSubscriberRemove(uuid: UUID)

// A simple Redis channel subscriber which will forward any Message to its parent
class RedisUuidSubscriber()
  extends RedisSubscriberActor(new InetSocketAddress("localhost", 6379), Seq(), Seq()) {

    def onMessage(message: Message) {
      context.parent ! message
    }

    def onPMessage(pmessage: PMessage) = Unit

    override def receive = {

      case RedisUuidSubscriberAdd(uuid: UUID) =>
        subscribe("uuid:" + uuid)

      case RedisUuidSubscriberRemove(uuid: UUID) =>
        unsubscribe("uuid:" + uuid)

      case other =>
        super.receive(other)
    }
}

Best regards,

Using set for a large number gets slower as we move from 100,000 to 1 million keys

I'm trying to run a simple test by putting 1 million keys-values into Redis. For 100,000 keys it is really fast. However, the performance degrades a lot when I bump the number of operations to 1 million. The max. heapspace is 12G and I'm running this on a Macbook pro. As you can see the network write drops significantly after sometime. Not sure what's going on here. Any help would be really appreciated.

I'm using the following versions:
"com.etaty.rediscala" %% "rediscala" % "1.4.0"
scalaVersion := "2.11.4"

package redisbenchmark

import akka.util.ByteString

import scala.concurrent.{Future}
import redis.RedisClient

import java.util.UUID

object RedisLocalPerf {

def main(args:Array[String]) = {
implicit val akkaSystem = akka.actor.ActorSystem()

var numberRuns = 1000 //default to 100
var size = 1
if( args.length == 1 )
  numberRuns = Integer.parseInt(args(0))


val s = """How to explain ZeroMQ? Some of us start by saying all the wonderful things it does. It's sockets on steroids. It's like mailboxes with routing. It's fast! Others try to share their moment of enlightenment, that zap-pow-kaboom satori paradigm-shift moment when it all became obvious. Things just become simpler. Complexity goes away. It opens the mind. Others try to explain by comparison. It's smaller, simpler, but still looks familiar. Personally, I like to remember why we made ZeroMQ at all, because that's most likely where you, the reader, still are today.How to explain ZeroMQ? Some of us start by saying all the wonderful things it does. It's sockets on steroids. It's like mailboxes with routing. It's fast! Others try to share their moment of enlightenment, that zap-pow-kaboom satori paradigm-shift moment when it all became obvious. Things just become simpler. Complexity goes away. It opens the mind. Others try to explain by comparison. It's smaller, simpler, but still looks familiar. Personally, I like to remember why we made ZeroMQ at all, because that's most likely where"""

val msgSize = s.getBytes.size
val redis = RedisClient()
implicit val ec = redis.executionContext

val futurePong = redis.ping()
println("Ping sent!")
futurePong.map(pong => {
  println(s"Redis replied with a $pong")
})

val random = UUID.randomUUID().toString
val start = System.currentTimeMillis()
val result: Seq[Future[Boolean]] = for {i <- 1 to numberRuns} yield {
  redis.set(random + i.toString, ByteString(s))
}
val res: Future[List[Boolean]] = Future.sequence(result.toList)
val end = System.currentTimeMillis()
val diff = (end - start)
println(s"for msgSize $msgSize and numOfRuns [$numberRuns] time is $diff ms ")
akkaSystem.shutdown()

}

}

image

Logging & loglevel for RedisWorkerIO

First of all, thank you for your efforts and contributions towards this package - it is very intuitive and useful.

However, the logging inside of RedisWorkerIO is a problem. Currently it binds to the implicit ActorSystem's LoggingAdapter (context.system.log) and I haven't found a reasonable way to silence connection/disconnection logging. It does not use getLogger like elsewhere in the code to provide for slf4j or log4j contextual logging. The loglevel in the reference.conf is not applied to Redis actors at all.

Disconnections are set to WARNING level, and reconnections are are INFO level. This is very annoying and chatty to run against a production Redis instance which frequently disconnects long-lived redis clients (reconnection handled by the driver).

Could you please update the logging to mute the particularly egregious WARN levels or apply a specific LoggingAdapter (log4j or slf4j style)? I have forks for both - can open a pull.

Thank you!

Read-Modify-Write transactions

Sorry if this is obvious but I could not find any example in the transaction spec or other documentation that shows how to handle futures for transactions that need to read in order to decide what to do inside the transaction.

Let's say I want a transaction that read the value of A, checks for a condition on it and if it is fulfilled modifies a value for B. In plain redis I would use WATCH, GET A, MULTI, SET B and EXEC.

In rediscala watch is part of the transaction, and It does not return its own future. So I'm unsure how to proceed. I need to know when the watch has been received before doing GET and I need to keep watching and I can't execute the whole transaction since I'm still building it. I'm not sure if I should have two separate transactions, but the session semantics are not present, so I'm unsure if the watches will still be valid then.

So overall, how do you do this kind of thing?

Another example: http://stackoverflow.com/questions/10750626/transactions-and-watch-statement-in-redis

HTTP Basic Auth support

Correct me if Iโ€™m wrong, but it seems there is no way to connect to a server that requires Basic Auth, e.g. RedisCloud.

pom files at etaty/rediscala-mvn seem to have character encoding issues

this
https://raw.githubusercontent.com/etaty/rediscala-mvn/master/releases/com/etaty/rediscala/rediscala_2.10/1.3/rediscala_2.10-1.3.pom
seems to be rendered as invalid xml for some reason. It's weird since it used to work

[warn] ==== rediscala: tried
[warn]   https://raw.githubusercontent.com/etaty/rediscala-mvn/master/releases/com/etaty/rediscala/rediscala_2.10/1.3/rediscala_2.10-1.3.pom
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  ::          UNRESOLVED DEPENDENCIES         ::
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  :: com.etaty.rediscala#rediscala_2.10;1.3: not found
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
sbt.ResolveException: unresolved dependency: com.etaty.rediscala#rediscala_2.10;1.3: not found

I created a mirror of the mvn repo here http://pk11-scratch.googlecode.com/svn/trunk/com/etaty/ if that helps.

unable to download source xalan/serializer

I am using rediscala 1.4.0 in my play application and when i run sbt to download sources(i need them to use debugger in idea 14) with idea with-sources=yes or idea sbt-classifiers i get this error


[warn]  [FAILED     ] xalan#serializer;2.7.1!serializer.jar(src):  (0ms)
[warn] ==== local: tried
[warn]   /home/lovesh/.ivy2/local/xalan/serializer/2.7.1/srcs/serializer-sources.jar
[warn] ==== public: tried
[warn]   http://repo1.maven.org/maven2/xalan/serializer/2.7.1/serializer-2.7.1-sources.jar
[warn] ==== Typesafe Releases Repository: tried
[warn]   http://repo.typesafe.com/typesafe/releases/xalan/serializer/2.7.1/serializer-2.7.1-sources.jar
[warn] ==== Typesafe Releases: tried
[warn]   http://repo.typesafe.com/typesafe/releases/xalan/serializer/2.7.1/serializer-2.7.1-sources.jar
[warn] ==== rediscala: tried
[warn]   http://dl.bintray.com/etaty/maven/xalan/serializer/2.7.1/serializer-2.7.1-sources.jar
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  ::              FAILED DOWNLOADS            ::
[warn]  :: ^ see resolution messages for details  ^ ::
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  :: xalan#serializer;2.7.1!serializer.jar(src)
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::```

I beleive this error occurs because rediscala depends on this source. How can i resolve this?

Bug in Operation class

In the Operation class, line 10, if you replace:

completeSuccess(r.get._1)

with

if (r.isDefined) completeSuccess(r.get._1)

then it won't crash when the redis response comes in more than one chunk (bytestring)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.