Skip to content

Asynchronous Connections

Mark Paluch edited this page Jul 9, 2015 · 6 revisions

lettuce is built on netty which is a multithreaded, event-driven IO framework. All communication is handled asynchronously. Every command sent to redis is also a future, which can be cancelled, awaited and listened on (derived from Guava's ListenableFuture). You can obtain a connection by calling the connectAsync() method of the RedisClient (or RedisClusterClient).

There are in general 4 ways how to wait or get notified in case a future completes:

  1. RedisFuture.get() / RedisFuture.get(long timeout, TimeUnit unit)
  2. while(!RedisFuture.isDone())
  3. RedisFuture.await(long timeout, TimeUnit unit)
  4. RedisFuture.addListener(Runnable runnable, Executor executor)

Synchronization using RedisFuture.get()

You can fire this way one or more commands and wait until the execution completes. If you use RedisFuture.get() the system will wait indefinitely and block your call. RedisFuture.get(long timeout, TimeUnit unit) will wait at most until the specified timeout. If the result comes back earlier, so you call will continue also earlier. If the timeout is exceeded, you'll receive a TimeoutException.

Synchronization using isDone()

In this style you are asing the Future whether it's done. You can poll, wait or even do other things until your future comes back. isDone is a non-blocking call.

Waiting using await(long timeout, TimeUnit unit)

You can specify a maximal waiting time, like in the get(long timeout, TimeUnit unit) example. The difference to get() is, that await(long timeout, TimeUnit unit) will come back with a boolean value in every case. So if the execution takes longer than the timeout, await will return false instead of a TimeoutException. After a result of true you can call get() and you'll receive immediately the return value.

Listerner notification

You can design your flow also completly asynchronous using listeners. You subscribe to a individual future using addListener(Runnable runnable, Executor executor). After the completion of the future you'll receive a call to run() of your supplied runnable. If the future is completed at the moment you call addListener(), you'll get immediately called.

Exceptions

Any redis errors will cause to return null on calling get(). If you are interested in the error, so you can access the message using getError() on your future. RedisException won't be thrown (in contrast to synchronous execution).

Examples

Basic operations

RedisStringsConnection<String, String> async = client.connectAsync()
RedisFuture<String> set = async.set("key", "value")
RedisFuture<String> get = async.get("key")

set.get() == "OK"
get.get() == "value"

Waiting for a future with a timeout

RedisStringsConnection<String, String> async = client.connectAsync()
RedisFuture<String> set = async.set("key", "value")
RedisFuture<String> get = async.get("key")

set.await(1, SECONDS) == true
set.get() == "OK"
get.get(1, TimeUnit.MINUTES) == "value"

Using listeners for a future

RedisStringsConnection<String, String> async = client.connectAsync()
RedisFuture<String> set = async.set("key", "value")

Runnable listener = new Runnable() {
    @Override
    public void run() {
            ...;
    }
};

set.addListener(listener, MoreExecutors.sameThreadExecutor());
Clone this wiki locally