Monday 30 January 2017

Redis - setting redis query timeouts using Lettuce in java

While writing applications, sometimes we need to get the data within a particular time, and if the time taken by the redis or the networks is more than a particular time, the application may not want to wait that long for the data to come back and may take some other route.

This is particularly important in scenarios like getting the user profiles while writing adservers where the overall response time is expected to be less than 100 ms, and if any component takes more than a few milliseconds, it should be discarded and the flow should continue without it. In the above scenarios, to make sure that the requests are served as fast as possible, while having a backup plan(how to get the required data in case the timeout happens from redis), it is a good idea to set the timeout.

Normally redis is very fast, and can serve data in a few microseconds(1 microsecond is a thousandth of a millisecond), but it is possible that the network between the redis and the application is slow and it is leading to slow queries.

The Redis client library in Java, Lettuce, provides a way for the application to set a timeout on the query. This way, the application for only wait for that time for the response to come back, otherwise it will proceed by throwing a timeout exception.

You will need the following entry in pom.xml file.

<dependency>
    <groupId>biz.paluch.redis</groupId>
    <artifactId>lettuce</artifactId>
    <version>4.3.0.Final</version>
</dependency>


The below code demonstrates the same.

public static void main(String[] args) {
String key = "testKey";
String value = null;

RedisURI uri = RedisURI.create("localhost", 6379);
RedisClient client = RedisClient.create(uri);

/*
* Normal way
*/
RedisCommands<String, String> commands = client.connect().sync();
System.out.println(commands.get(key));


/* 
* Reactive way
*/
RedisReactiveCommands<String, String> reactiveCommand = client.connect().reactive();
rx.Observable<String> observable = reactiveCommand.get(key);

try{
value = observable.timeout(100, TimeUnit.MILLISECONDS).toBlocking().singleOrDefault(null);
} catch (RuntimeException e) {
if (e.getCause() instanceof TimeoutException){
System.out.println("timeout exception thrown");
}
}

System.out.println(value);
reactiveCommand.close();



The above code shows both ways to get the data using Lettuce Client, ie. Normal way and the reactive way.
In the normal way, we get the data from redis regardless of how long redis(and the network) take to return the data.
However, in the reactive way, if the value of "testkey" in not returned within 100 ms, a Timeout exception wrapped inside RuntimeException is thrown.

The application may handle the exception and take whatever it needs to do(like get the user's profile from a different source or ignore the user's profile altogether, treating it as a new user or depending on the business use case).

Note that it is a good idea to log such timeouts and analyse the reasons if the timeouts occur very frequently.

:)