Coder Social home page Coder Social logo

redis / lettuce Goto Github PK

View Code? Open in Web Editor NEW
5.3K 208.0 939.0 21.32 MB

Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.

Home Page: https://lettuce.io

License: MIT License

Java 94.59% Makefile 0.23% Shell 0.06% HTML 0.01% CSS 0.60% Kotlin 4.51%
java redis asynchronous reactive redis-sentinel redis-cluster azure-redis-cache aws-elasticache redis-client

lettuce's Introduction

Lettuce - Advanced Java Redis client

Maven Central

Lettuce is a scalable thread-safe Redis client for synchronous, asynchronous and reactive usage. Multiple threads may share one connection if they avoid blocking and transactional operations such as BLPOP and MULTI/EXEC. Lettuce is built with netty. Supports advanced Redis features such as Sentinel, Cluster, Pipelining, Auto-Reconnect and Redis data models.

This version of Lettuce has been tested against the latest Redis source-build.

See the reference documentation and Wiki for more details.

How do I Redis?

Learn for free at Redis University

Build faster with the Redis Launchpad

Try the Redis Cloud

Dive in developer tutorials

Join the Redis community

Work at Redis

Communication

Documentation

Binaries/Download

Binaries and dependency information for Maven, Ivy, Gradle and others can be found at http://search.maven.org.

Releases of lettuce are available in the Maven Central repository. Take also a look at the Releases.

Example for Maven:

<dependency>
  <groupId>io.lettuce</groupId>
  <artifactId>lettuce-core</artifactId>
  <version>x.y.z</version>
</dependency>

If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository and declare the appropriate dependency version.

<dependency>
  <groupId>io.lettuce</groupId>
  <artifactId>lettuce-core</artifactId>
  <version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>

<repositories>
  <repository>
    <id>sonatype-snapshots</id>
    <name>Sonatype Snapshot Repository</name>
    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

Basic Usage

RedisClient client = RedisClient.create("redis://localhost");
StatefulRedisConnection<String, String> connection = client.connect();
RedisStringCommands sync = connection.sync();
String value = sync.get("key");

Each Redis command is implemented by one or more methods with names identical to the lowercase Redis command name. Complex commands with multiple modifiers that change the result type include the CamelCased modifier as part of the command name, e.g. zrangebyscore and zrangebyscoreWithScores.

See Basic usage for further details.

Asynchronous API

StatefulRedisConnection<String, String> connection = client.connect();
RedisStringAsyncCommands<String, String> async = connection.async();
RedisFuture<String> set = async.set("key", "value")
RedisFuture<String> get = async.get("key")

LettuceFutures.awaitAll(set, get) == true

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

See Asynchronous API for further details.

Reactive API

StatefulRedisConnection<String, String> connection = client.connect();
RedisStringReactiveCommands<String, String> reactive = connection.reactive();
Mono<String> set = reactive.set("key", "value");
Mono<String> get = reactive.get("key");

set.subscribe();

get.block() == "value"

See Reactive API for further details.

Pub/Sub

RedisPubSubCommands<String, String> connection = client.connectPubSub().sync();
connection.getStatefulConnection().addListener(new RedisPubSubListener<String, String>() { ... })
connection.subscribe("channel")

Building

Lettuce is built with Apache Maven. The tests require multiple running Redis instances for different test cases which are configured using a Makefile. Tests run by default against Redis unstable.

To build:

$ git clone https://github.com/lettuce-io/lettuce-core.git
$ cd lettuce/
$ make prepare ssl-keys
$ make test
  • Initial environment setup (clone and build redis): make prepare
  • Setup SSL Keys: make ssl-keys
  • Run the build: make test
  • Start Redis (manually): make start
  • Stop Redis (manually): make stop

Bugs and Feedback

For bugs, questions and discussions please use the GitHub Issues.

License

Contributing

Github is for social coding: if you want to write code, I encourage contributions through pull requests from forks of this repository. Create Github tickets for bugs and new features and comment on the ones that you are interested in and take a look into CONTRIBUTING.md

lettuce's People

Contributors

atakavci avatar be-hase avatar dengliming avatar dmandalidis avatar dowenliu-xyz avatar gkorland avatar hashzhang avatar hellyguo avatar jongyeol avatar jruaux avatar kichik avatar koisyu avatar larrybattle avatar mp911de avatar perlun avatar rohannagar avatar schnapster avatar sergey-ushakov avatar shikharid avatar sokomishalov avatar sullis avatar taer avatar tgrall avatar tishun avatar twz123 avatar uglide avatar wg avatar worldtiki avatar yangbodong22011 avatar yueki1993 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  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

lettuce's Issues

API Fixes on 3.0

  • Add isOpen to sentinel connection
  • Fix clusterSlaves on sync cluster connection interfaces
  • Generalize syncHandler in AbstractRedisClient

Change value datatype to long for PUBSUB NUMSUB output

Tests fail due to missing implementation of MapOutput.setInteger. Adjust map value datatype for PUBSUB NUMSUBcommand to Long.

java.lang.IllegalStateException
    at com.lambdaworks.redis.protocol.CommandOutput.set(CommandOutput.java:60)
    at com.lambdaworks.redis.protocol.RedisStateMachine.decode(RedisStateMachine.java:121)
    at com.lambdaworks.redis.protocol.CommandHandler.decode(CommandHandler.java:101)
    at com.lambdaworks.redis.protocol.CommandHandler.channelRead(CommandHandler.java:89)

Memory leak

The following code works for a while but stops receiving messages very quickly. When run without the debugger, I actually get the following error messages:

15/01/09 21:36:50 WARN channel.DefaultChannelPipeline: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.OutOfMemoryError: Java heap space

To expedite the process I limit JVM memory with -Xmx32m. However, I first discovered this issue while running a production server with 6GB heap size. It was under very low load and received a small message every 20 seconds. At some point I noticed messages were not being delivered anymore and the logs threw the same OOM errors. A heap dump showed buffer in com.lambdaworks.redis.protocol.CommanHandler was a holding a contiguous 1GB array. It was trying to extend the buffer, but had no more huge contiguous blocks in the heap.

I am weirdly unable to reproduce the OOM in a debugger. However, when running in a debugger, I still do get the same issue with messages not being received after a while.

import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;

import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisURI;
import com.lambdaworks.redis.codec.Utf8StringCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubConnectionImpl;
import com.lambdaworks.redis.pubsub.RedisPubSubListener;


public class LettuceMemoryLeak implements RedisPubSubListener<String, String>
{

    private static Logger LOGGER = Logger.getLogger( "LettuceMemoryLeak" );


    public static void main( String[] args ) throws InterruptedException, ExecutionException
    {
        RedisURI uri = RedisURI.Builder.sentinel( "localhost", 26379, "mymaster" ).build();
        RedisClient client = new RedisClient( uri );

        RedisPubSubConnectionImpl<String, String> subscriber = client.connectPubSub( new Utf8StringCodec() );
        subscriber.subscribe( "test" );
        subscriber.addListener( new LettuceMemoryLeak() );

        RedisConnection<String, String> publisher = client.connect( new Utf8StringCodec() );

        char[] chars = new char[8096];
        Arrays.fill( chars, 'a' );
        String str = new String( chars );

        while( true ) {
            publisher.publish( "test", str );
        }
    }


    @Override
    public void message( String channel, String message )
    {
        LOGGER.info( channel );
    }


    @Override
    public void message( String pattern, String channel, String message )
    {
    }


    @Override
    public void subscribed( String channel, long count )
    {
        LOGGER.info( "subscribed to " + channel + " " + count );
    }


    @Override
    public void psubscribed( String pattern, long count )
    {
    }


    @Override
    public void unsubscribed( String channel, long count )
    {
    }


    @Override
    public void punsubscribed( String pattern, long count )
    {
    }

}

I'll update this ticket once I have more information.

RedisClusterConnection stops operation after .RedisCommandTimeoutException

Setup: current master checkout of 3.1-SNAPSHOT: One thread, which has a single RedisClusterConnection<String,String>

The thread does a hgetall in a loop. You want to force a timeout on this thread. Do so by placing a VM breakpoint(pause all threads) in Utf8StringCodec.decode(). Let this hang for a bit(60 seconds I believe is the default timeout)

Now, once you're sure you've expired the timeout, remove the breakpoint and resume the JVM. The command you paused will throw from
FutureSyncInvocationHandler:59 return LettuceFutures.await(command, timeout, unit);

It doesn't seem to occur on a normal RedisConnection.

This is as far as I have made it. What happens next is the original caller gets an exception, which is perfectly fine. However, future calls to hgetall on the same connection will now simply timeout.

! com.lambdaworks.redis.RedisCommandTimeoutException: Command timed out
! at com.lambdaworks.redis.LettuceFutures.await(LettuceFutures.java:68) ~[tanknew1.jar:na]
! at com.lambdaworks.redis.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:59) ~[tanknew1.jar:na]
! at com.lambdaworks.com.google.common.reflect.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:87) ~[tanknew1.jar:na]
! at com.sun.proxy.$Proxy95.hgetall(Unknown Source) ~[na:na]

Additional info: The pause all threads didn't seem to matter. I updated to just pause the single thread in the decode, and it broke the same way.

That was how to reproduce the error. Here is all I've managed to dig up so far.

Did a Thread dump. I have numerous requests blocked waiting for lock on
com.lambdaworks.redis.RedisAsyncConnectionImpl.dispatch()

The guy who has that monitor is blocked on
at com.lambdaworks.redis.protocol.Command.get(Command.java:109)
which is a CountDownLatch.await()

Memory leak on connection loss

There seems to be a memory leak on reconnection. This seems to be related to a very specific way of the connection going down because I don't always see it and I only see it together with the state exception.

I'm using Netty 4.0.25 with pooled buffers -Dio.netty.allocator.type=pooled
To get the stack I use -Dio.netty.leakDetectionLevel=advanced
Latest lettuce 3.0.2.

2015-01-30 16:21:17,932 WARN io.netty.channel.DefaultChannelPipeline: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
com.lambdaworks.redis.RedisException: Invalid first byte: 111
        at com.lambdaworks.redis.protocol.RedisStateMachine.readReplyType(RedisStateMachine.java:200)
        at com.lambdaworks.redis.protocol.RedisStateMachine.decode(RedisStateMachine.java:98)
        at com.lambdaworks.redis.protocol.RedisStateMachine.decode(RedisStateMachine.java:61)
        at com.lambdaworks.redis.pubsub.PubSubCommandHandler.decode(PubSubCommandHandler.java:55)
        at com.lambdaworks.redis.protocol.CommandHandler.channelRead(CommandHandler.java:89)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
        at java.lang.Thread.run(Thread.java:744)
2015-01-30 16:21:17,935 ERROR io.netty.util.ResourceLeakDetector: LEAK: ByteBuf.release() was not called before it's garbage-collected.
Recent access records: 0
Created at:
        io.netty.buffer.PooledByteBufAllocator.newHeapBuffer(PooledByteBufAllocator.java:240)
        io.netty.buffer.AbstractByteBufAllocator.heapBuffer(AbstractByteBufAllocator.java:136)
        io.netty.buffer.AbstractByteBufAllocator.heapBuffer(AbstractByteBufAllocator.java:122)
        com.lambdaworks.redis.protocol.CommandHandler.channelRegistered(CommandHandler.java:59)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:133)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:119)
        io.netty.channel.ChannelInboundHandlerAdapter.channelRegistered(ChannelInboundHandlerAdapter.java:42)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:133)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:119)
        io.netty.channel.ChannelInboundHandlerAdapter.channelRegistered(ChannelInboundHandlerAdapter.java:42)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:133)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:119)
        io.netty.channel.ChannelInboundHandlerAdapter.channelRegistered(ChannelInboundHandlerAdapter.java:42)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:133)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:119)
        io.netty.channel.ChannelInitializer.channelRegistered(ChannelInitializer.java:71)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:133)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:119)
        io.netty.channel.DefaultChannelPipeline.fireChannelRegistered(DefaultChannelPipeline.java:733)
        io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:449)
        io.netty.channel.AbstractChannel$AbstractUnsafe.access$100(AbstractChannel.java:377)
        io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:423)
        io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
        io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
        io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
        io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
        java.lang.Thread.run(Thread.java:744)

I'll share more information when I find it.

Provide a stateful redis connection and decouple sync/async API from connection resources

3.x code:

RedisConnection connection = client.connect();

4.x code:

StatefulRedisConnection stateful = client.connect();
RedisConnection connection = stateful.sync();

The other connect methods like connectAsync and connectSentinelAsync will remain unchanged.

Affected connect methods are:

  • RedisClient.connect (provides a StatefulRedisConnection)
  • RedisClient.connectPubSub (provides a StatefulRedisPubSubConnection)
  • RedisClusterClient.connect (provides a StatefulRedisClusterConnection)

New connect methods:

  • RedisClient.connectSentinel (provides a StatefulRedisSentinelConnection)

RedisPubSubConnectionImpl.activated() deadlock

RedisPubSubConnectionImpl.activated() can deadlock if another thread is trying to subscribe or unsubscribe at the same time. RedisPubSubConnectionImpl.subscribe() calls RedisAsyncConnectionImpl.dispatch() which is synchronized. RedisAsyncConnectionImpl.dispatch() calls CommandHandler.write() which tries to get writeLock. CommandHandler.channelActive() holds writeLock and calls RedisPubSubConnectionImpl.activated() which calls RedisPubSubConnectionImpl.subscribe() and tries to get the object lock held by the other thread trying to subscribe.

So basically:

  • CommandHandler.channelActive() holds writeLock and tries to get RedisAsyncConnectionImpl object lock
  • RedisPubSubConnectionImpl.subscribe() holds RedisAsyncConnectionImpl object lock and then tries to get writeLock

Fix URL parsing

  • Extract URL parser in own class to enable reuse
  • Fix password/sentinel parsing when supplying multiple hosts

Confusing project and artifact layout

The project consists of 3 maven modules: parent, lettuce and lettuce shaded. All are deployed to mvn central. Searching for lettuce causes to appear all three artifacts.

Expected: Simplify layout to one maven module, add shaded jar as additional artifact with shaded classifier. This removes the separate parent and lettuce-shaded artifacts.

Improve CRC16 calculation to use lookup table

Use an improved calculation.

The CRC16 is specified as follows:

  • Name: XMODEM (also known as ZMODEM or CRC-16/ACORN)
  • Width: 16 bit
  • Poly: 1021 (That is actually x16 + x12 + x5 + 1)
  • Initialization: 0000
  • Reflect Input byte: False
  • Reflect Output CRC: False
  • Xor constant to output CRC: 0000
  • Output for "123456789": 31C3

Allow reset on internal connection state

The internal state machine could run into an invalid state due to network failures, VM errors or unexpected/faulty Redis responses (i.e. version does not fit the Redis client).

This could be handled by closing the connection and reconnecting for getting a clear and defined state without any "backlog" on the TCP connection.

Introduce ClientOptions to control specific behavior

Add new ClientOptions type at AbstractRedisClient level (something like AbstractRedisClient#options()) to control:

  • PING before enable the connection (default to false)
  • Auto-Reconnect (default to true)
  • Cancel commands on reconnect failures (default to false)

Support NX|XX|CH|INCR options in ZADD

ZADD options (Redis 3.0.2 or greater)
ZADD supports a list of options, specified after the name of the key and before the first score argument. Options are:

  • XX: Only update elements that already exist. Never add elements.
  • NX: Don't update already existing elements. Always add new elements.
  • CH: Modify the return value from the number of new elements added, to the total number of elements changed (CH is an abbreviation of changed). Changed elements are new elements added and elements already existing for which the score was updated. So elements specified in the command line having the same score as they had in the past are not counted. Note: normally the return value of ZADD only counts the number of new elements added.
  • INCR: When this option is specified ZADD acts like ZINCRBY. Only one score-element pair can be specified in this mode.

ERR MULTI calls can not be nested

my code:
public static void main(String[] args) throws Exception {
final RedisConnection<String, byte[]> sync = new RedisClient("10.58.52.60", 5021)
.connect(new BytesCodec());
sync.flushall();

     final CountDownLatch c = new CountDownLatch(1);
        new Thread(new Runnable() {
            public void run() {
                try {
                    c.await();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                sync.multi();
                sync.set("a", Thread.currentThread().getName().getBytes());
                sync.set("a1", Thread.currentThread().getName().getBytes());
                System.out.println(1234);
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                try {
                    c.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sync.multi();
                sync.set("a", Thread.currentThread().getName().getBytes());
                sync.set("a1", Thread.currentThread().getName().getBytes());
                sync.exec();
                System.out.println(5678);
            }
        }).start();

        c.countDown();


}

output:
Exception in thread "Thread-2" com.lambdaworks.redis.RedisCommandExecutionException: ERR MULTI calls can not be nested
at com.lambdaworks.redis.LettuceFutures.await(LettuceFutures.java:76)
at com.lambdaworks.redis.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:59)
at com.google.common.reflect.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:87)
at $Proxy5.multi(Unknown Source)
at com.lambdaworks.redis.AsyncConnectionConcurrentTest$2.run(AsyncConnectionConcurrentTest.java:44)
at java.lang.Thread.run(Thread.java:662)
1234

Enhance lettuce resilience

Generic exceptions (i.e. protocol exceptions, exceptions on callback to pubsub notifications) can lead to a defective internal state. It might be worth to provide a reconnect-on-exception functionality. This ticket needs further investigation and was opened due to #21

Add checks for arguments

Arguments to redis commands are currently not checked at all. Empty arrays, empty values (SLAVEOF, CLIENT KILL) and null values in arrays can be passed to redis

Additional cluster tests (new suite)

Methods:
clusterAddSlots
clusterDelSlots
clusterSetSlotNode
clusterSetSlotMigrating
clusterSetSlotImporting
clusterFlushslots
clusterFailover
clusteReset

SSL support

Implement SSL support to connect to redis running behind a stunnel

Reactive support

Add another layer between command creation and execution (today a command is created and immediately executed). Reactive commands should be only executed (example from RxJava as soon as call is invoked).

This layer could be located between the command builder and the async connection itself.

NPE in MultiOutput when nested Output is null

java.lang.NullPointerException
    at com.lambdaworks.redis.output.MultiOutput.set(MultiOutput.java:48)
    at com.lambdaworks.redis.output.MultiOutput.set(MultiOutput.java:48)
    at com.lambdaworks.redis.protocol.RedisStateMachine.decode(RedisStateMachine.java:108)
    at com.lambdaworks.redis.protocol.CommandHandler.decode(CommandHandler.java:101)
    at com.lambdaworks.redis.protocol.CommandHandler.channelRead(CommandHandler.java:89)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:341)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:327)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:341)

Add tests for untested code

hvals (streaming)
migrate
mget (streaming)
sdiff (streaming)
sinter (streaming)
smembers (streaming)
sort (streaming)
srandmember (streaming)
wait
zrange (streaming)
zrangeWithScores
zrangebyscore
zrangebyscoreWithScores
zrevrange
zrevrangeWithScores
zrevrangebyscore
zrevrangebyscoreWithScores
scan (streaming)
sscan (streaming)
hscan (streaming)
zscan (streaming)

Expose futures of re-subscription on reconnect

RedisPubSubConnectionImpl re-subscribes to patterns and channels on reconnects but these futures are not accessible. Adding a protected List<RedisFuture<Void>> resubscribe() will allow accessing these futures.

JavaDoc compatibility with Java 8

Rework JavaDocs for Java8 compatibility:

[ERROR] Exit code: 1 - javadoc: warning - Error fetching URL: http://netty.io/4.0/api
[ERROR] javadoc: warning - Error fetching URL: http://commons.apache.org/proper/commons-pool/api-2.2
[ERROR] javadoc: warning - Error fetching URL: http://docs.guava-libraries.googlecode.com/git/javadoc
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/codec/CRC16.java:48: warning: no description for @param
[ERROR] * @param bytes
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java:216: error: unterminated inline tag
[ERROR] * @param listener must not be {@literal null
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java:47: warning: no description for @param
[ERROR] * @param channels
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java:92: warning: no description for @param
[ERROR] * @param script
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java:139: warning: no description for @param
[ERROR] * @param replicas
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java:140: warning: no description for @param
[ERROR] * @param timeout
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java:46: warning: no description for @param
[ERROR] * @param channels
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java:69: error: semicolon missing
[ERROR] * @return List&lt;Object&gt array-reply where the first element is one of master, slave, sentinel and the additional
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java:91: warning: no description for @param
[ERROR] * @param script
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java:137: warning: no description for @param
[ERROR] * @param replicas
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java:138: warning: no description for @param
[ERROR] * @param timeout
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScanCursor.java:24: warning: no description for @param
[ERROR] * @param cursor
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScanCursor.java:45: warning: no description for @param
[ERROR] * @param cursor
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/KeyValue.java:18: warning: no description for @param
[ERROR] * @param key
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/KeyValue.java:19: warning: no description for @param
[ERROR] * @param value
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/LettuceFutures.java:65: warning: no @param for <K>
[ERROR] public static <K, V, T> T await(RedisCommand<K, V, T> cmd, long timeout, TimeUnit unit) {
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/LettuceFutures.java:65: warning: no @param for <V>
[ERROR] public static <K, V, T> T await(RedisCommand<K, V, T> cmd, long timeout, TimeUnit unit) {
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/LettuceFutures.java:65: warning: no @param for <T>
[ERROR] public static <K, V, T> T await(RedisCommand<K, V, T> cmd, long timeout, TimeUnit unit) {
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/LettuceStrings.java:4: error: bad use of '>'
[ERROR] * @author <a href="mailto:[email protected]">Mark Paluch</a>>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java:21: warning: no description for @param
[ERROR] * @param timeout
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java:22: warning: no description for @param
[ERROR] * @param unit
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java:29: warning: no description for @param
[ERROR] * @param db
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java:37: warning: no description for @param
[ERROR] * @param password
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:196: warning: no @param for key
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:196: warning: no @return
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:201: warning: no @param for key
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:201: warning: no @param for scanArgs
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:201: warning: no @return
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:206: warning: no @param for key
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:206: warning: no @param for scanCursor
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:206: warning: no @param for scanArgs
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:206: warning: no @return
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:211: warning: no @param for key
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:211: warning: no @param for scanCursor
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:211: warning: no @return
[ERROR] RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:216: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:216: warning: no @param for key
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:216: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:221: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:221: warning: no @param for key
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:221: warning: no @param for scanArgs
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:221: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:231: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:236: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:236: warning: no @param for key
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:236: warning: no @param for scanCursor
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java:236: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:132: warning: no description for @param
[ERROR] * @param key
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:140: warning: no description for @param
[ERROR] * @param key
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:244: warning: no @param for key
[ERROR] RedisFuture<List<V>> sort(K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:251: warning: no @param for channel
[ERROR] RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:251: warning: no @param for key
[ERROR] RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:258: warning: no @param for key
[ERROR] RedisFuture<List<V>> sort(K key, SortArgs sortArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:258: warning: no @param for sortArgs
[ERROR] RedisFuture<List<V>> sort(K key, SortArgs sortArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:265: warning: no @param for channel
[ERROR] RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key, SortArgs sortArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:265: warning: no @param for key
[ERROR] RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key, SortArgs sortArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:265: warning: no @param for sortArgs
[ERROR] RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key, SortArgs sortArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:290: warning: no @return
[ERROR] RedisFuture<KeyScanCursor<K>> scan();
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:295: warning: no @param for scanArgs
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:295: warning: no @return
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:300: warning: no @param for scanCursor
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:300: warning: no @param for scanArgs
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:300: warning: no @return
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:305: warning: no @param for scanCursor
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:305: warning: no @return
[ERROR] RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:310: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:310: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:315: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:315: warning: no @param for scanArgs
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:315: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:320: warning: no description for @param
[ERROR] * @param channel
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:322: warning: no description for @param
[ERROR] * @param scanArgs
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:324: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:329: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:329: warning: no @param for scanCursor
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java:329: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:208: warning: no @param for key
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:208: warning: no @return
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:213: warning: no @param for key
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:213: warning: no @param for scanArgs
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:213: warning: no @return
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:218: warning: no @param for key
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:218: warning: no @param for scanCursor
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:218: warning: no @param for scanArgs
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:218: warning: no @return
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:223: warning: no @param for key
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:223: warning: no @param for scanCursor
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:223: warning: no @return
[ERROR] RedisFuture<ValueScanCursor<V>> sscan(K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:228: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:228: warning: no @param for key
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:228: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:233: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:233: warning: no @param for key
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:233: warning: no @param for scanArgs
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:233: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:238: warning: no description for @param
[ERROR] * @param channel
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:241: warning: no description for @param
[ERROR] * @param scanArgs
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:243: warning: no @return
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanCursor scanCursor, ScanArgs scanArgs);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:248: warning: no @param for channel
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java:248: warning: no @param for key
[ERROR] RedisFuture<StreamScanCursor> sscan(ValueStreamingChannel<V> channel, K key, ScanCursor scanCursor);
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java:158: error: malformed HTML
[ERROR] * @return RedisChannelWriter<K, V>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java:158: error: bad use of '>'
[ERROR] * @return RedisChannelWriter<K, V>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java:21: error: malformed HTML
[ERROR] * @return RedisCommand<K, V, T>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java:21: error: bad use of '>'
[ERROR] * @return RedisCommand<K, V, T>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisClient.java:111: error: malformed HTML
[ERROR] * @return RedisConnectionPool<RedisConnection<K, V>>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisClient.java:111: error: malformed HTML
[ERROR] * @return RedisConnectionPool<RedisConnection<K, V>>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisClient.java:111: error: bad use of '>'
[ERROR] * @return RedisConnectionPool<RedisConnection<K, V>>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisClient.java:111: error: bad use of '>'
[ERROR] * @return RedisConnectionPool<RedisConnection<K, V>>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisListsConnection.java:22: error: malformed HTML
[ERROR] * @return KeyValue<K,V> array-reply specifically:
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisListsConnection.java:22: error: bad use of '>'
[ERROR] * @return KeyValue<K,V> array-reply specifically:
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisListsConnection.java:35: error: malformed HTML
[ERROR] * @return KeyValue<K,V> array-reply specifically:
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/RedisListsConnection.java:35: error: bad use of '>'
[ERROR] * @return KeyValue<K,V> array-reply specifically:
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:13: error: text not allowed in <ul> element
[ERROR] * <li>{@link #MULTI} of these types</li>.
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:20: error: bad use of '>'
[ERROR] * <li>Redis integer reply -> Lua number</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:21: error: bad use of '>'
[ERROR] * <li>Redis bulk reply -> Lua string</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:22: error: bad use of '>'
[ERROR] * <li>Redis multi bulk reply -> Lua table (may have other Redis data types nested)</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:23: error: bad use of '>'
[ERROR] * <li>Redis status reply -> Lua table with a single <code>ok</code> field containing the status</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:24: error: bad use of '>'
[ERROR] * <li>Redis error reply -> Lua table with a single <code>err</code> field containing the error</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:25: error: bad use of '>'
[ERROR] * <li>Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:31: error: bad use of '>'
[ERROR] * <li>Lua number -> Redis integer reply (the number is converted into an integer)</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:32: error: bad use of '>'
[ERROR] * <li>Lua string -> Redis bulk reply</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:33: error: bad use of '>'
[ERROR] * <li>Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:34: error: bad use of '>'
[ERROR] * <li>Lua table with a single <code>ok</code> field -> Redis status reply</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:35: error: bad use of '>'
[ERROR] * <li>Lua table with a single <code>err</code> field -> Redis error reply</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/ScriptOutputType.java:36: error: bad use of '>'
[ERROR] * <li>Lua boolean false -> Redis Nil bulk reply.</li>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java:19: error: malformed HTML
[ERROR] * @return CommandOutput<K, V, T>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java:19: error: bad use of '>'
[ERROR] * @return CommandOutput<K, V, T>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java:30: error: malformed HTML
[ERROR] * @return CommandArgs<K, V>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java:30: error: bad use of '>'
[ERROR] * @return CommandArgs<K, V>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/support/RedisClientFactoryBean.java:14: error: self-closing element not allowed
[ERROR] * </code> <br/>
[ERROR] ^
[ERROR] /Users/mark/git/lettuce/src/main/java/com/lambdaworks/redis/support/package-info.java:2: error: reference not found
[ERROR] * Supportive classes such as {@link com.lambdaworks.redis.support.CdiProducer} for CDI support, {@link com.lambdaworks.redis.support.RedisClientFactoryBean} for Spring.
[ERROR] ^
[ERROR] 
[ERROR] Command line was: /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/bin/javadoc @options @packages

Enhance stability when reconnecting

Commands can run into a "won't ever come back" state when lettuce tries to reconnect but fails while reconnecting/re-issuing commands.

Desired behavior:
Either re-issue/retry commands on each reconnect or cancel commands after the reconnect failed but not loose commands.

See #31 (comment) for details

@Kitchik: Will continue parts of #31 here. What do you think about the desired behavior?

Change build environment to JDK8

Use JDK8 for build but still support Java 6 and 7. Depends on JavaDoc compatibility with Java 8 #39 and requires to have a test project in order to ensure lettuce usage on JDK6/7/8

Migrate RedisFuture to CompletionStage

Need input on this topic. The current RedisFuture is a limited facility in terms of async. The underlying ListenableFuture provides a very basic functionality. Chaining and promises are hard to achieve.

Commands have Output fields that are nullable and mutable.

Commands can be created with null outputs. I think this could be cleaned up to require non-null Outputs. I think we should also remove the setOutput() call on command as well. Output is used in the RedisStateMachine, and changing output midstream or having a missing one can lead to issues.

From an initial look, only 2 commands have no output. The debugOOM and debugSegfault. Both these kill the server, so there is no output to report. I wasn't able to find any other places where a null output is used.

If this seems OK, I'd like to go down this path.

Also, is this the best way to discuss code proposals like this?

Handle absence of optional epoll library in a reasonable way

When a RedisURI is created without the epoll library on the class path the result is a ClassNotFoundError. This should be changed to:

  1. lettuce should work without epoll for regular operations
  2. Throw a qualified exception in case the user wants to use sockets but the library is not available

Provide an option to connect to Redis via Unix Domain Sockets

Having an option to connect to a local Redis via UDS would be nice to have. It's allegedly faster.
From: http://redis.io/topics/benchmarks

Depending on the platform, unix domain sockets can achieve around 50% more throughput than the TCP/IP loopback (on Linux for instance)

Netty supports UDS in 4.0.26
https://twitter.com/normanmaurer/status/573090616000843777

Additional info from chat

mostly adding a new schemes to RedisURI, say redis-socket and redis-sentinel-socket or something like that then upgrading to latest netty, adding the socket resolution and maybe some bootstrap options.

Provide access to cluster connection using the advanced cluster API

Provide access to cluster connections with using an advanced cluster API

RedisAdvancedClusterConnection and RedisAdvancedClusterAsyncConnection

Methods on RedisAdvancedClusterConnection:

RedisClusterConnection getConnection(String nodeId)
RedisClusterConnection getConnection(String host, int port)

and Methods on RedisAdvancedClusterAsyncConnection

RedisClusterAsyncConnection getConnection(String nodeId)
RedisClusterAsyncConnection getConnection(String host, int port)

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.