diff --git a/opentracing-redis-jedis/pom.xml b/opentracing-redis-jedis/pom.xml
index d0ef4b0..2d0da76 100644
--- a/opentracing-redis-jedis/pom.xml
+++ b/opentracing-redis-jedis/pom.xml
@@ -46,6 +46,13 @@
       embedded-redis
       test
     
+
+    
+      org.testcontainers
+      testcontainers
+      1.17.4
+      test
+    
   
 
 
\ No newline at end of file
diff --git a/opentracing-redis-jedis/src/main/java/io/opentracing/contrib/redis/jedis/TracingJedisCluster.java b/opentracing-redis-jedis/src/main/java/io/opentracing/contrib/redis/jedis/TracingJedisCluster.java
index feb9c6b..8397474 100644
--- a/opentracing-redis-jedis/src/main/java/io/opentracing/contrib/redis/jedis/TracingJedisCluster.java
+++ b/opentracing-redis-jedis/src/main/java/io/opentracing/contrib/redis/jedis/TracingJedisCluster.java
@@ -14,11 +14,6 @@
 package io.opentracing.contrib.redis.jedis;
 
 import static io.opentracing.contrib.redis.common.TracingHelper.nullable;
-import static io.opentracing.contrib.redis.common.TracingHelper.onError;
-
-import io.opentracing.Span;
-import io.opentracing.contrib.redis.common.TracingConfiguration;
-import io.opentracing.contrib.redis.common.TracingHelper;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -28,6 +23,9 @@
 import java.util.Set;
 import java.util.function.Function;
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import io.opentracing.Span;
+import io.opentracing.contrib.redis.common.TracingConfiguration;
+import io.opentracing.contrib.redis.common.TracingHelper;
 import redis.clients.jedis.BinaryClient.LIST_POSITION;
 import redis.clients.jedis.BinaryJedisPubSub;
 import redis.clients.jedis.BitOP;
@@ -169,14 +167,7 @@ public TracingJedisCluster(Set jedisClusterNode, int connectionTime
   public String set(String key, String value) {
     Span span = helper.buildSpan("set", key);
     span.setTag("value", value);
-    try {
-      return super.set(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.set(key, value));
   }
 
   @Override
@@ -186,14 +177,7 @@ public String set(String key, String value, String nxxx, String expx, long time)
     span.setTag("nxxx", nxxx);
     span.setTag("expx", expx);
     span.setTag("time", time);
-    try {
-      return super.set(key, value, nxxx, expx, time);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.set(key, value, nxxx, expx, time));
   }
 
   @Override
@@ -208,66 +192,31 @@ public String set(String key, String value, String expx, long time) {
   @Override
   public String get(String key) {
     Span span = helper.buildSpan("get", key);
-    try {
-      return super.get(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.get(key));
   }
 
   @Override
   public Long exists(String... keys) {
     Span span = helper.buildSpan("exists", keys);
-    try {
-      return super.exists(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.exists(keys));
   }
 
   @Override
   public Boolean exists(String key) {
     Span span = helper.buildSpan("exists", key);
-    try {
-      return super.exists(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.exists(key));
   }
 
   @Override
   public Long del(String... keys) {
     Span span = helper.buildSpan("del", keys);
-    try {
-      return super.del(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.del(keys));
   }
 
   @Override
   public Long del(String key) {
     Span span = helper.buildSpan("del", key);
-    try {
-      return super.del(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.del(key));
   }
 
   @Override
@@ -285,14 +234,7 @@ public Long unlink(String... keys) {
   @Override
   public String type(String key) {
     Span span = helper.buildSpan("type", key);
-    try {
-      return super.type(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.type(key));
   }
 
   @Override
@@ -314,14 +256,7 @@ public String rename(String oldkey, String newkey) {
     Span span = helper.buildSpan("rename");
     span.setTag("oldKey", nullable(oldkey));
     span.setTag("newKey", nullable(newkey));
-    try {
-      return super.rename(oldkey, newkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rename(oldkey, newkey));
   }
 
   @Override
@@ -329,55 +264,27 @@ public Long renamenx(String oldkey, String newkey) {
     Span span = helper.buildSpan("renamenx");
     span.setTag("oldKey", nullable(oldkey));
     span.setTag("newKey", nullable(newkey));
-    try {
-      return super.renamenx(oldkey, newkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.renamenx(oldkey, newkey));
   }
 
   @Override
   public Long expire(String key, int seconds) {
     Span span = helper.buildSpan("expire", key);
     span.setTag("seconds", seconds);
-    try {
-      return super.expire(key, seconds);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.expire(key, seconds));
   }
 
   @Override
   public Long expireAt(String key, long unixTime) {
     Span span = helper.buildSpan("expireAt", key);
     span.setTag("unixTime", unixTime);
-    try {
-      return super.expireAt(key, unixTime);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.expireAt(key, unixTime));
   }
 
   @Override
   public Long ttl(String key) {
     Span span = helper.buildSpan("ttl", key);
-    try {
-      return super.ttl(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.ttl(key));
   }
 
   @Override
@@ -396,55 +303,27 @@ public Long touch(String... keys) {
   public Long move(String key, int dbIndex) {
     Span span = helper.buildSpan("move", key);
     span.setTag("dbIndex", dbIndex);
-    try {
-      return super.move(key, dbIndex);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.move(key, dbIndex));
   }
 
   @Override
   public String getSet(String key, String value) {
     Span span = helper.buildSpan("getSet", key);
     span.setTag("value", value);
-    try {
-      return super.getSet(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getSet(key, value));
   }
 
   @Override
   public List mget(String... keys) {
     Span span = helper.buildSpan("mget", keys);
-    try {
-      return super.mget(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.mget(keys));
   }
 
   @Override
   public Long setnx(String key, String value) {
     Span span = helper.buildSpan("setnx", key);
     span.setTag("value", value);
-    try {
-      return super.setnx(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setnx(key, value));
   }
 
   @Override
@@ -452,124 +331,61 @@ public String setex(String key, int seconds, String value) {
     Span span = helper.buildSpan("setex", key);
     span.setTag("seconds", seconds);
     span.setTag("value", value);
-    try {
-      return super.setex(key, seconds, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setex(key, seconds, value));
   }
 
   @Override
   public String mset(String... keysvalues) {
     Span span = helper.buildSpan("mset");
     span.setTag("keysvalues", Arrays.toString(keysvalues));
-    try {
-      return super.mset(keysvalues);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.mset(keysvalues));
   }
 
   @Override
   public Long msetnx(String... keysvalues) {
     Span span = helper.buildSpan("msetnx");
     span.setTag("keysvalues", Arrays.toString(keysvalues));
-    try {
-      return super.msetnx(keysvalues);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.msetnx(keysvalues));
   }
 
   @Override
   public Long decrBy(String key, long integer) {
     Span span = helper.buildSpan("decrBy", key);
     span.setTag("integer", integer);
-    try {
-      return super.decrBy(key, integer);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.decrBy(key, integer));
   }
 
   @Override
   public Long decr(String key) {
     Span span = helper.buildSpan("decr", key);
-    try {
-      return super.decr(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.decr(key));
   }
 
   @Override
   public Long incrBy(String key, long integer) {
     Span span = helper.buildSpan("incrBy", key);
     span.setTag("integer", integer);
-    try {
-      return super.incrBy(key, integer);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.incrBy(key, integer));
   }
 
   @Override
   public Double incrByFloat(String key, double value) {
     Span span = helper.buildSpan("incrByFloat", key);
     span.setTag("value", value);
-    try {
-      return super.incrByFloat(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.incrByFloat(key, value));
   }
 
   @Override
   public Long incr(String key) {
     Span span = helper.buildSpan("incr", key);
-    try {
-      return super.incr(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.incr(key));
   }
 
   @Override
   public Long append(String key, String value) {
     Span span = helper.buildSpan("append", key);
     span.setTag("value", value);
-    try {
-      return super.append(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.append(key, value));
   }
 
   @Override
@@ -577,14 +393,7 @@ public String substr(String key, int start, int end) {
     Span span = helper.buildSpan("substr", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.substr(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.substr(key, start, end));
   }
 
   @Override
@@ -592,14 +401,7 @@ public Long hset(String key, String field, String value) {
     Span span = helper.buildSpan("hset", key);
     span.setTag("field", field);
     span.setTag("value", value);
-    try {
-      return super.hset(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hset(key, field, value));
   }
 
   @Override
@@ -613,14 +415,7 @@ public Long hset(String key, Map hash) {
   public String hget(String key, String field) {
     Span span = helper.buildSpan("hget", key);
     span.setTag("field", field);
-    try {
-      return super.hget(key, field);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hget(key, field));
   }
 
   @Override
@@ -628,42 +423,21 @@ public Long hsetnx(String key, String field, String value) {
     Span span = helper.buildSpan("hsetnx", key);
     span.setTag("field", field);
     span.setTag("value", value);
-    try {
-      return super.hsetnx(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hsetnx(key, field, value));
   }
 
   @Override
   public String hmset(String key, Map hash) {
     Span span = helper.buildSpan("hmset", key);
     span.setTag("hash", TracingHelper.toString(hash));
-    try {
-      return super.hmset(key, hash);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hmset(key, hash));
   }
 
   @Override
   public List hmget(String key, String... fields) {
     Span span = helper.buildSpan("hmget", key);
     span.setTag("fields", Arrays.toString(fields));
-    try {
-      return super.hmget(key, fields);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hmget(key, fields));
   }
 
   @Override
@@ -671,14 +445,7 @@ public Long hincrBy(String key, String field, long value) {
     Span span = helper.buildSpan("hincrBy", key);
     span.setTag("field", field);
     span.setTag("value", value);
-    try {
-      return super.hincrBy(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hincrBy(key, field, value));
   }
 
   @Override
@@ -686,135 +453,65 @@ public Double hincrByFloat(String key, String field, double value) {
     Span span = helper.buildSpan("hincrByFloat", key);
     span.setTag("field", field);
     span.setTag("value", value);
-    try {
-      return super.hincrByFloat(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hincrByFloat(key, field, value));
   }
 
   @Override
   public Boolean hexists(String key, String field) {
     Span span = helper.buildSpan("hexists", key);
     span.setTag("field", field);
-    try {
-      return super.hexists(key, field);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hexists(key, field));
   }
 
   @Override
   public Long hdel(String key, String... fields) {
     Span span = helper.buildSpan("hdel", key);
     span.setTag("fields", Arrays.toString(fields));
-    try {
-      return super.hdel(key, fields);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hdel(key, fields));
   }
 
   @Override
   public Long hlen(String key) {
     Span span = helper.buildSpan("hlen", key);
-    try {
-      return super.hlen(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hlen(key));
   }
 
   @Override
   public Set hkeys(String key) {
     Span span = helper.buildSpan("hkeys", key);
-    try {
-      return super.hkeys(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hkeys(key));
   }
 
   @Override
   public List hvals(String key) {
     Span span = helper.buildSpan("hvals", key);
-    try {
-      return super.hvals(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hvals(key));
   }
 
   @Override
   public Map hgetAll(String key) {
     Span span = helper.buildSpan("hgetAll", key);
-    try {
-      return super.hgetAll(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hgetAll(key));
   }
 
   @Override
   public Long rpush(String key, String... strings) {
     Span span = helper.buildSpan("rpush", key);
     span.setTag("strings", Arrays.toString(strings));
-    try {
-      return super.rpush(key, strings);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpush(key, strings));
   }
 
   @Override
   public Long lpush(String key, String... strings) {
     Span span = helper.buildSpan("lpush", key);
     span.setTag("strings", Arrays.toString(strings));
-    try {
-      return super.lpush(key, strings);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lpush(key, strings));
   }
 
   @Override
   public Long llen(String key) {
     Span span = helper.buildSpan("llen", key);
-    try {
-      return super.llen(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.llen(key));
   }
 
   @Override
@@ -822,14 +519,7 @@ public List lrange(String key, long start, long end) {
     Span span = helper.buildSpan("lrange", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.lrange(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lrange(key, start, end));
   }
 
   @Override
@@ -837,28 +527,14 @@ public String ltrim(String key, long start, long end) {
     Span span = helper.buildSpan("ltrim", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.ltrim(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.ltrim(key, start, end));
   }
 
   @Override
   public String lindex(String key, long index) {
     Span span = helper.buildSpan("lindex", key);
     span.setTag("index", index);
-    try {
-      return super.lindex(key, index);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lindex(key, index));
   }
 
   @Override
@@ -866,14 +542,7 @@ public String lset(String key, long index, String value) {
     Span span = helper.buildSpan("lset", key);
     span.setTag("index", index);
     span.setTag("value", value);
-    try {
-      return super.lset(key, index, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lset(key, index, value));
   }
 
   @Override
@@ -881,40 +550,19 @@ public Long lrem(String key, long count, String value) {
     Span span = helper.buildSpan("lrem", key);
     span.setTag("count", count);
     span.setTag("value", value);
-    try {
-      return super.lrem(key, count, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lrem(key, count, value));
   }
 
   @Override
   public String lpop(String key) {
     Span span = helper.buildSpan("lpop", key);
-    try {
-      return super.lpop(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lpop(key));
   }
 
   @Override
   public String rpop(String key) {
     Span span = helper.buildSpan("rpop", key);
-    try {
-      return super.rpop(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpop(key));
   }
 
   @Override
@@ -922,82 +570,40 @@ public String rpoplpush(String srckey, String dstkey) {
     Span span = helper.buildSpan("rpoplpush");
     span.setTag("srckey", srckey);
     span.setTag("dstkey", dstkey);
-    try {
-      return super.rpoplpush(srckey, dstkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpoplpush(srckey, dstkey));
   }
 
   @Override
   public Long sadd(String key, String... members) {
     Span span = helper.buildSpan("sadd", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.sadd(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sadd(key, members));
   }
 
   @Override
   public Set smembers(String key) {
     Span span = helper.buildSpan("smembers", key);
-    try {
-      return super.smembers(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.smembers(key));
   }
 
   @Override
   public Long srem(String key, String... members) {
     Span span = helper.buildSpan("srem", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.srem(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.srem(key, members));
   }
 
   @Override
   public String spop(String key) {
     Span span = helper.buildSpan("spop", key);
-    try {
-      return super.spop(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.spop(key));
   }
 
   @Override
   public Set spop(String key, long count) {
     Span span = helper.buildSpan("spop", key);
     span.setTag("count", count);
-    try {
-      return super.spop(key, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.spop(key, count));
   }
 
   @Override
@@ -1006,149 +612,72 @@ public Long smove(String srckey, String dstkey, String member) {
     span.setTag("srckey", srckey);
     span.setTag("dstkey", dstkey);
     span.setTag("member", member);
-    try {
-      return super.smove(srckey, dstkey, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.smove(srckey, dstkey, member));
   }
 
   @Override
   public Long scard(String key) {
     Span span = helper.buildSpan("scard", key);
-    try {
-      return super.scard(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scard(key));
   }
 
   @Override
   public Boolean sismember(String key, String member) {
     Span span = helper.buildSpan("sismember", key);
     span.setTag("member", member);
-    try {
-      return super.sismember(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sismember(key, member));
   }
 
   @Override
   public Set sinter(String... keys) {
     Span span = helper.buildSpan("sinter", keys);
-    try {
-      return super.sinter(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sinter(keys));
   }
 
   @Override
   public Long sinterstore(String dstkey, String... keys) {
     Span span = helper.buildSpan("sinterstore", keys);
     span.setTag("dstkey", dstkey);
-    try {
-      return super.sinterstore(dstkey, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sinterstore(dstkey, keys));
   }
 
   @Override
   public Set sunion(String... keys) {
     Span span = helper.buildSpan("sunion", keys);
-    try {
-      return super.sunion(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sunion(keys));
   }
 
   @Override
   public Long sunionstore(String dstkey, String... keys) {
     Span span = helper.buildSpan("sunionstore", keys);
     span.setTag("dstkey", dstkey);
-    try {
-      return super.sunionstore(dstkey, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sunionstore(dstkey, keys));
   }
 
   @Override
   public Set sdiff(String... keys) {
     Span span = helper.buildSpan("sdiff", keys);
-    try {
-      return super.sdiff(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sdiff(keys));
   }
 
   @Override
   public Long sdiffstore(String dstkey, String... keys) {
     Span span = helper.buildSpan("sdiffstore", keys);
     span.setTag("dstkey", dstkey);
-    try {
-      return super.sdiffstore(dstkey, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sdiffstore(dstkey, keys));
   }
 
   @Override
   public String srandmember(String key) {
     Span span = helper.buildSpan("srandmember", key);
-    try {
-      return super.srandmember(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.srandmember(key));
   }
 
   @Override
   public List srandmember(String key, int count) {
     Span span = helper.buildSpan("srandmember", key);
     span.setTag("count", count);
-    try {
-      return super.srandmember(key, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.srandmember(key, count));
   }
 
   @Override
@@ -1156,14 +685,7 @@ public Long zadd(String key, double score, String member) {
     Span span = helper.buildSpan("zadd", key);
     span.setTag("score", score);
     span.setTag("member", member);
-    try {
-      return super.zadd(key, score, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, score, member));
   }
 
   @Override
@@ -1172,28 +694,14 @@ public Long zadd(String key, double score, String member, ZAddParams params) {
     span.setTag("score", score);
     span.setTag("member", member);
     span.setTag("params", TracingHelper.toString(params.getByteParams()));
-    try {
-      return super.zadd(key, score, member, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, score, member, params));
   }
 
   @Override
   public Long zadd(String key, Map scoreMembers) {
     Span span = helper.buildSpan("zadd", key);
     span.setTag("scoreMembers", TracingHelper.toString(scoreMembers));
-    try {
-      return super.zadd(key, scoreMembers);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, scoreMembers));
   }
 
   @Override
@@ -1201,14 +709,7 @@ public Long zadd(String key, Map scoreMembers, ZAddParams params
     Span span = helper.buildSpan("zadd", key);
     span.setTag("scoreMembers", TracingHelper.toString(scoreMembers));
     span.setTag("params", TracingHelper.toString(params.getByteParams()));
-    try {
-      return super.zadd(key, scoreMembers, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, scoreMembers, params));
   }
 
   @Override
@@ -1216,28 +717,14 @@ public Set zrange(String key, long start, long end) {
     Span span = helper.buildSpan("zrange", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrange(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrange(key, start, end));
   }
 
   @Override
   public Long zrem(String key, String... members) {
     Span span = helper.buildSpan("zrem", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.zrem(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrem(key, members));
   }
 
   @Override
@@ -1245,14 +732,7 @@ public Double zincrby(String key, double score, String member) {
     Span span = helper.buildSpan("zincrby", key);
     span.setTag("score", score);
     span.setTag("member", member);
-    try {
-      return super.zincrby(key, score, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zincrby(key, score, member));
   }
 
   @Override
@@ -1261,42 +741,21 @@ public Double zincrby(String key, double score, String member, ZIncrByParams par
     span.setTag("score", score);
     span.setTag("member", member);
     span.setTag("params", TracingHelper.toString(params.getByteParams()));
-    try {
-      return super.zincrby(key, score, member, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zincrby(key, score, member, params));
   }
 
   @Override
   public Long zrank(String key, String member) {
     Span span = helper.buildSpan("zrank", key);
     span.setTag("member", member);
-    try {
-      return super.zrank(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrank(key, member));
   }
 
   @Override
   public Long zrevrank(String key, String member) {
     Span span = helper.buildSpan("zrevrank", key);
     span.setTag("member", member);
-    try {
-      return super.zrevrank(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrank(key, member));
   }
 
   @Override
@@ -1304,14 +763,7 @@ public Set zrevrange(String key, long start, long end) {
     Span span = helper.buildSpan("zrevrange", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrevrange(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrange(key, start, end));
   }
 
   @Override
@@ -1319,14 +771,7 @@ public Set zrangeWithScores(String key, long start, long end) {
     Span span = helper.buildSpan("zrangeWithScores", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrangeWithScores(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeWithScores(key, start, end));
   }
 
   @Override
@@ -1334,111 +779,54 @@ public Set zrevrangeWithScores(String key, long start, long end) {
     Span span = helper.buildSpan("zrevrangeWithScores", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrevrangeWithScores(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeWithScores(key, start, end));
   }
 
   @Override
   public Long zcard(String key) {
     Span span = helper.buildSpan("zcard", key);
-    try {
-      return super.zcard(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zcard(key));
   }
 
   @Override
   public Double zscore(String key, String member) {
     Span span = helper.buildSpan("zscore", key);
     span.setTag("member", member);
-    try {
-      return super.zscore(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscore(key, member));
   }
 
-
   @Override
   public List sort(String key) {
     Span span = helper.buildSpan("sort", key);
-    try {
-      return super.sort(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key));
   }
 
   @Override
   public List sort(String key, SortingParams sortingParameters) {
     Span span = helper.buildSpan("sort", key);
     span.setTag("sortingParameters", TracingHelper.toString(sortingParameters.getParams()));
-    try {
-      return super.sort(key, sortingParameters);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key, sortingParameters));
   }
 
   @Override
   public List blpop(int timeout, String... keys) {
     Span span = helper.buildSpan("blpop", keys);
     span.setTag("timeout", timeout);
-    try {
-      return super.blpop(timeout, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.blpop(timeout, keys));
   }
 
   @Override
   public List blpop(String arg) {
     Span span = helper.buildSpan("blpop");
     span.setTag("arg", arg);
-    try {
-      return super.blpop(arg);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.blpop(arg));
   }
 
   @Override
   public List brpop(String arg) {
     Span span = helper.buildSpan("brpop");
     span.setTag("arg", arg);
-    try {
-      return super.brpop(arg);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.brpop(arg));
   }
 
   @Override
@@ -1446,42 +834,21 @@ public Long sort(String key, SortingParams sortingParameters, String dstkey) {
     Span span = helper.buildSpan("sort", key);
     span.setTag("sortingParameters", TracingHelper.toString(sortingParameters.getParams()));
     span.setTag("dstkey", dstkey);
-    try {
-      return super.sort(key, sortingParameters, dstkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key, sortingParameters, dstkey));
   }
 
   @Override
   public Long sort(String key, String dstkey) {
     Span span = helper.buildSpan("sort", key);
     span.setTag("dstkey", dstkey);
-    try {
-      return super.sort(key, dstkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key, dstkey));
   }
 
   @Override
   public List brpop(int timeout, String... keys) {
     Span span = helper.buildSpan("brpop", keys);
     span.setTag("timeout", timeout);
-    try {
-      return super.brpop(timeout, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.brpop(timeout, keys));
   }
 
   @Override
@@ -1489,14 +856,7 @@ public Long zcount(String key, double min, double max) {
     Span span = helper.buildSpan("zcount", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zcount(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zcount(key, min, max));
   }
 
   @Override
@@ -1504,14 +864,7 @@ public Long zcount(String key, String min, String max) {
     Span span = helper.buildSpan("zcount", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zcount(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zcount(key, min, max));
   }
 
   @Override
@@ -1519,14 +872,7 @@ public Set zrangeByScore(String key, double min, double max) {
     Span span = helper.buildSpan("zrangeByScore", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByScore(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max));
   }
 
   @Override
@@ -1534,14 +880,7 @@ public Set zrangeByScore(String key, String min, String max) {
     Span span = helper.buildSpan("zrangeByScore", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByScore(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max));
   }
 
   @Override
@@ -1551,14 +890,7 @@ public Set zrangeByScore(String key, double min, double max, int offset,
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScore(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max, offset, count));
   }
 
   @Override
@@ -1568,14 +900,7 @@ public Set zrangeByScore(String key, String min, String max, int offset,
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScore(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max, offset, count));
   }
 
   @Override
@@ -1583,14 +908,7 @@ public Set zrangeByScoreWithScores(String key, double min, double max) {
     Span span = helper.buildSpan("zrangeByScoreWithScores", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max));
   }
 
   @Override
@@ -1598,14 +916,7 @@ public Set zrangeByScoreWithScores(String key, String min, String max) {
     Span span = helper.buildSpan("zrangeByScoreWithScores", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max));
   }
 
   @Override
@@ -1616,14 +927,7 @@ public Set zrangeByScoreWithScores(String key, double min, double max, in
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max, offset, count));
   }
 
   @Override
@@ -1634,14 +938,7 @@ public Set zrangeByScoreWithScores(String key, String min, String max, in
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max, offset, count));
   }
 
   @Override
@@ -1649,14 +946,7 @@ public Set zrevrangeByScore(String key, double max, double min) {
     Span span = helper.buildSpan("zrevrangeByScore", key);
     span.setTag("max", max);
     span.setTag("min", min);
-    try {
-      return super.zrevrangeByScore(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min));
   }
 
   @Override
@@ -1664,14 +954,7 @@ public Set zrevrangeByScore(String key, String max, String min) {
     Span span = helper.buildSpan("zrevrangeByScore", key);
     span.setTag("max", max);
     span.setTag("min", min);
-    try {
-      return super.zrevrangeByScore(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min));
   }
 
   @Override
@@ -1681,14 +964,7 @@ public Set zrevrangeByScore(String key, double max, double min, int offs
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScore(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min, offset, count));
   }
 
   @Override
@@ -1696,14 +972,7 @@ public Set zrevrangeByScoreWithScores(String key, double max, double min)
     Span span = helper.buildSpan("zrevrangeByScoreWithScores", key);
     span.setTag("max", max);
     span.setTag("min", min);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min));
   }
 
   @Override
@@ -1714,14 +983,7 @@ public Set zrevrangeByScoreWithScores(String key, double max, double min,
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min, offset, count));
   }
 
   @Override
@@ -1732,14 +994,7 @@ public Set zrevrangeByScoreWithScores(String key, String max, String min,
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min, offset, count));
   }
 
   @Override
@@ -1749,14 +1004,7 @@ public Set zrevrangeByScore(String key, String max, String min, int offs
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScore(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min, offset, count));
   }
 
   @Override
@@ -1764,14 +1012,7 @@ public Set zrevrangeByScoreWithScores(String key, String max, String min)
     Span span = helper.buildSpan("zrevrangeByScoreWithScores", key);
     span.setTag("max", max);
     span.setTag("min", min);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min));
   }
 
   @Override
@@ -1779,14 +1020,7 @@ public Long zremrangeByRank(String key, long start, long end) {
     Span span = helper.buildSpan("zremrangeByRank", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zremrangeByRank(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByRank(key, start, end));
   }
 
   @Override
@@ -1794,14 +1028,7 @@ public Long zremrangeByScore(String key, double start, double end) {
     Span span = helper.buildSpan("zremrangeByScore", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zremrangeByScore(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByScore(key, start, end));
   }
 
   @Override
@@ -1809,14 +1036,7 @@ public Long zremrangeByScore(String key, String start, String end) {
     Span span = helper.buildSpan("zremrangeByScore", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zremrangeByScore(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByScore(key, start, end));
   }
 
   @Override
@@ -1824,14 +1044,7 @@ public Long zunionstore(String dstkey, String... sets) {
     Span span = helper.buildSpan("zunionstore");
     span.setTag("dstkey", dstkey);
     span.setTag("sets", Arrays.toString(sets));
-    try {
-      return super.zunionstore(dstkey, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zunionstore(dstkey, sets));
   }
 
   @Override
@@ -1839,14 +1052,7 @@ public Long zunionstore(String dstkey, ZParams params, String... sets) {
     Span span = helper.buildSpan("zunionstore");
     span.setTag("params", TracingHelper.toString(params.getParams()));
     span.setTag("sets", Arrays.toString(sets));
-    try {
-      return super.zunionstore(dstkey, params, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zunionstore(dstkey, params, sets));
   }
 
   @Override
@@ -1854,14 +1060,7 @@ public Long zinterstore(String dstkey, String... sets) {
     Span span = helper.buildSpan("zinterstore");
     span.setTag("dstkey", dstkey);
     span.setTag("sets", Arrays.toString(sets));
-    try {
-      return super.zinterstore(dstkey, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zinterstore(dstkey, sets));
   }
 
   @Override
@@ -1870,14 +1069,7 @@ public Long zinterstore(String dstkey, ZParams params, String... sets) {
     span.setTag("dstkey", dstkey);
     span.setTag("params", TracingHelper.toString(params.getParams()));
     span.setTag("sets", Arrays.toString(sets));
-    try {
-      return super.zinterstore(dstkey, params, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zinterstore(dstkey, params, sets));
   }
 
   @Override
@@ -1885,14 +1077,7 @@ public Long zlexcount(String key, String min, String max) {
     Span span = helper.buildSpan("zlexcount", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zlexcount(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zlexcount(key, min, max));
   }
 
   @Override
@@ -1900,14 +1085,7 @@ public Set zrangeByLex(String key, String min, String max) {
     Span span = helper.buildSpan("zrangeByLex", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByLex(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByLex(key, min, max));
   }
 
   @Override
@@ -1917,14 +1095,7 @@ public Set zrangeByLex(String key, String min, String max, int offset, i
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByLex(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByLex(key, min, max, offset, count));
   }
 
   @Override
@@ -1932,14 +1103,7 @@ public Set zrevrangeByLex(String key, String max, String min) {
     Span span = helper.buildSpan("zrevrangeByLex", key);
     span.setTag("max", max);
     span.setTag("min", min);
-    try {
-      return super.zrevrangeByLex(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByLex(key, max, min));
   }
 
   @Override
@@ -1949,14 +1113,7 @@ public Set zrevrangeByLex(String key, String max, String min, int offset
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByLex(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByLex(key, max, min, offset, count));
   }
 
   @Override
@@ -1964,82 +1121,40 @@ public Long zremrangeByLex(String key, String min, String max) {
     Span span = helper.buildSpan("zremrangeByLex", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zremrangeByLex(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByLex(key, min, max));
   }
 
   @Override
   public Long strlen(String key) {
     Span span = helper.buildSpan("strlen", key);
-    try {
-      return super.strlen(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.strlen(key));
   }
 
   @Override
   public Long lpushx(String key, String... string) {
     Span span = helper.buildSpan("lpushx", key);
     span.setTag("string", Arrays.toString(string));
-    try {
-      return super.lpushx(key, string);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lpushx(key, string));
   }
 
   @Override
   public Long persist(String key) {
     Span span = helper.buildSpan("persist", key);
-    try {
-      return super.persist(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.persist(key));
   }
 
   @Override
   public Long rpushx(String key, String... string) {
     Span span = helper.buildSpan("rpushx", key);
     span.setTag("string", Arrays.toString(string));
-    try {
-      return super.rpushx(key, string);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpushx(key, string));
   }
 
   @Override
   public String echo(String string) {
     Span span = helper.buildSpan("echo");
     span.setTag("string", string);
-    try {
-      return super.echo(string);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.echo(string));
   }
 
   @Override
@@ -2048,14 +1163,7 @@ public Long linsert(String key, LIST_POSITION where, String pivot, String value)
     span.setTag("where", where.name());
     span.setTag("pivot", pivot);
     span.setTag("value", value);
-    try {
-      return super.linsert(key, where, pivot, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.linsert(key, where, pivot, value));
   }
 
   @Override
@@ -2073,14 +1181,7 @@ public String brpoplpush(String source, String destination, int timeout) {
     span.setTag("source", source);
     span.setTag("destination", destination);
     span.setTag("timeout", timeout);
-    try {
-      return super.brpoplpush(source, destination, timeout);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.brpoplpush(source, destination, timeout));
   }
 
   @Override
@@ -2088,14 +1189,7 @@ public Boolean setbit(String key, long offset, boolean value) {
     Span span = helper.buildSpan("setbit", key);
     span.setTag("offset", offset);
     span.setTag("value", value);
-    try {
-      return super.setbit(key, offset, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setbit(key, offset, value));
   }
 
   @Override
@@ -2103,28 +1197,14 @@ public Boolean setbit(String key, long offset, String value) {
     Span span = helper.buildSpan("setbit", key);
     span.setTag("offset", offset);
     span.setTag("value", value);
-    try {
-      return super.setbit(key, offset, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setbit(key, offset, value));
   }
 
   @Override
   public Boolean getbit(String key, long offset) {
     Span span = helper.buildSpan("getbit", key);
     span.setTag("offset", offset);
-    try {
-      return super.getbit(key, offset);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getbit(key, offset));
   }
 
   @Override
@@ -2132,14 +1212,7 @@ public Long setrange(String key, long offset, String value) {
     Span span = helper.buildSpan("setrange", key);
     span.setTag("offset", offset);
     span.setTag("value", value);
-    try {
-      return super.setrange(key, offset, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setrange(key, offset, value));
   }
 
   @Override
@@ -2147,28 +1220,14 @@ public String getrange(String key, long startOffset, long endOffset) {
     Span span = helper.buildSpan("getrange", key);
     span.setTag("startOffset", startOffset);
     span.setTag("endOffset", endOffset);
-    try {
-      return super.getrange(key, startOffset, endOffset);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getrange(key, startOffset, endOffset));
   }
 
   @Override
   public Long bitpos(String key, boolean value) {
     Span span = helper.buildSpan("bitpos", key);
     span.setTag("value", value);
-    try {
-      return super.bitpos(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitpos(key, value));
   }
 
   @Override
@@ -2176,58 +1235,29 @@ public Long bitpos(String key, boolean value, BitPosParams params) {
     Span span = helper.buildSpan("bitpos", key);
     span.setTag("value", value);
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.bitpos(key, value, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitpos(key, value, params));
   }
 
-
   @Override
   public Object eval(String script, int keyCount, String... params) {
     Span span = helper.buildSpan("eval");
     span.setTag("keyCount", keyCount);
     span.setTag("params", Arrays.toString(params));
-    try {
-      return super.eval(script, keyCount, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, keyCount, params));
   }
 
   @Override
   public Object eval(String script, String key) {
     Span span = helper.buildSpan(Command.EVAL.name(), key);
     span.setTag("script", script);
-    try {
-      return super.eval(script, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, key));
   }
 
   @Override
   public void subscribe(JedisPubSub jedisPubSub, String... channels) {
     Span span = helper.buildSpan("subscribe");
     span.setTag("channels", Arrays.toString(channels));
-    try {
-      super.subscribe(jedisPubSub, channels);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    helper.decorate(span, () -> super.subscribe(jedisPubSub, channels));
   }
 
   @Override
@@ -2235,28 +1265,14 @@ public Long publish(String channel, String message) {
     Span span = helper.buildSpan("publish");
     span.setTag("channel", channel);
     span.setTag("message", message);
-    try {
-      return super.publish(channel, message);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.publish(channel, message));
   }
 
   @Override
   public void psubscribe(JedisPubSub jedisPubSub, String... patterns) {
     Span span = helper.buildSpan("psubscribe");
     span.setTag("patterns", Arrays.toString(patterns));
-    try {
-      super.psubscribe(jedisPubSub, patterns);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    helper.decorate(span, () -> super.psubscribe(jedisPubSub, patterns));
   }
 
   @Override
@@ -2264,14 +1280,7 @@ public Object eval(String script, List keys, List args) {
     Span span = helper.buildSpan("eval");
     span.setTag("keys", TracingHelper.toString(keys));
     span.setTag("args", TracingHelper.toString(args));
-    try {
-      return super.eval(script, keys, args);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, keys, args));
   }
 
   @Override
@@ -2280,70 +1289,35 @@ public Object evalsha(String sha1, List keys, List args) {
     span.setTag("keys", TracingHelper.toString(keys));
     span.setTag("args", TracingHelper.toString(args));
     span.setTag("sha1", sha1);
-    try {
-      return super.evalsha(sha1, keys, args);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.evalsha(sha1, keys, args));
   }
 
   @Override
   public Object evalsha(String script, String key) {
     Span span = helper.buildSpan(Command.EVALSHA.name(), key);
     span.setTag("script", script);
-    try {
-      return super.evalsha(script, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.evalsha(script, key));
   }
 
   @Override
   public Boolean scriptExists(String sha1, String key) {
     Span span = helper.buildSpan("scriptExists", key);
     span.setTag("sha1", sha1);
-    try {
-      return super.scriptExists(sha1, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptExists(sha1, key));
   }
 
   @Override
   public List scriptExists(String key, String... sha1) {
     Span span = helper.buildSpan("scriptExists", key);
     span.setTag("sha1", Arrays.toString(sha1));
-    try {
-      return super.scriptExists(key, sha1);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptExists(key, sha1));
   }
 
   @Override
   public String scriptLoad(String script, String key) {
     Span span = helper.buildSpan("scriptLoad", key);
     span.setTag("script", script);
-    try {
-      return super.scriptLoad(script, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptLoad(script, key));
   }
 
   @Override
@@ -2366,27 +1340,13 @@ public Object evalsha(String sha1, int keyCount, String... params) {
     span.setTag("keyCount", keyCount);
     span.setTag("params", Arrays.toString(params));
     span.setTag("sha1", sha1);
-    try {
-      return super.evalsha(sha1, keyCount, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.evalsha(sha1, keyCount, params));
   }
 
   @Override
   public Long bitcount(String key) {
     Span span = helper.buildSpan("bitcount", key);
-    try {
-      return super.bitcount(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitcount(key));
   }
 
   @Override
@@ -2394,14 +1354,7 @@ public Long bitcount(String key, long start, long end) {
     Span span = helper.buildSpan("bitcount", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.bitcount(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitcount(key, start, end));
   }
 
   @Override
@@ -2416,41 +1369,20 @@ public Long bitop(BitOP op, String destKey, String... srcKeys) {
     Span span = helper.buildSpan("bitop");
     span.setTag("destKey", destKey);
     span.setTag("srcKeys", Arrays.toString(srcKeys));
-    try {
-      return super.bitop(op, destKey, srcKeys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitop(op, destKey, srcKeys));
   }
 
   @Override
   public String ping() {
     Span span = helper.buildSpan("ping");
-    try {
-      return super.ping();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.ping());
   }
 
   @Override
   public String set(byte[] key, byte[] value) {
     Span span = helper.buildSpan("set", key);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.set(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.set(key, value));
   }
 
   @Override
@@ -2460,14 +1392,7 @@ public String set(byte[] key, byte[] value, byte[] nxxx, byte[] expx, long time)
     span.setTag("expx", Arrays.toString(expx));
     span.setTag("time", time);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.set(key, value, nxxx, expx, time);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.set(key, value, nxxx, expx, time));
   }
 
   @Override
@@ -2482,81 +1407,39 @@ public String set(byte[] key, byte[] value, byte[] expx, long time) {
   @Override
   public byte[] get(byte[] key) {
     Span span = helper.buildSpan("get", key);
-    try {
-      return super.get(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.get(key));
   }
 
   @Override
   public String quit() {
     Span span = helper.buildSpan("quit");
-    try {
-      return super.quit();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.quit());
   }
 
   @Override
   public Long exists(byte[]... keys) {
     Span span = helper.buildSpan("exists");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.exists(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.exists(keys));
   }
 
   @Override
   public Boolean exists(byte[] key) {
     Span span = helper.buildSpan("exists", key);
-    try {
-      return super.exists(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.exists(key));
   }
 
   @Override
   public Long del(byte[]... keys) {
     Span span = helper.buildSpan("del");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.del(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.del(keys));
   }
 
   @Override
   public Long del(byte[] key) {
     Span span = helper.buildSpan("del", key);
-    try {
-      return super.del(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.del(key));
   }
 
   @Override
@@ -2574,14 +1457,7 @@ public Long unlink(byte[]... keys) {
   @Override
   public String type(byte[] key) {
     Span span = helper.buildSpan("type", key);
-    try {
-      return super.type(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.type(key));
   }
 
   @Override
@@ -2601,14 +1477,7 @@ public String restore(byte[] key, int ttl, byte[] serializedValue) {
   @Override
   public String flushDB() {
     Span span = helper.buildSpan("flushDB");
-    try {
-      return super.flushDB();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.flushDB());
   }
 
   @Override
@@ -2616,14 +1485,7 @@ public String rename(byte[] oldkey, byte[] newkey) {
     Span span = helper.buildSpan("rename");
     span.setTag("oldkey", Arrays.toString(oldkey));
     span.setTag("newkey", Arrays.toString(newkey));
-    try {
-      return super.rename(oldkey, newkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rename(oldkey, newkey));
   }
 
   @Override
@@ -2631,82 +1493,40 @@ public Long renamenx(byte[] oldkey, byte[] newkey) {
     Span span = helper.buildSpan("renamenx");
     span.setTag("oldkey", Arrays.toString(oldkey));
     span.setTag("newkey", Arrays.toString(newkey));
-    try {
-      return super.renamenx(oldkey, newkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.renamenx(oldkey, newkey));
   }
 
   @Override
   public Long dbSize() {
     Span span = helper.buildSpan("dbSize");
-    try {
-      return super.dbSize();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.dbSize());
   }
 
   @Override
   public Long expire(byte[] key, int seconds) {
     Span span = helper.buildSpan("expire", key);
     span.setTag("seconds", seconds);
-    try {
-      return super.expire(key, seconds);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.expire(key, seconds));
   }
 
   @Override
   public Long pexpire(String key, long milliseconds) {
     Span span = helper.buildSpan("pexpire", key);
     span.setTag("milliseconds", milliseconds);
-    try {
-      return super.pexpire(key, milliseconds);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pexpire(key, milliseconds));
   }
 
   @Override
   public Long expireAt(byte[] key, long unixTime) {
     Span span = helper.buildSpan("expireAt", key);
     span.setTag("unixTime", unixTime);
-    try {
-      return super.expireAt(key, unixTime);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.expireAt(key, unixTime));
   }
 
   @Override
   public Long ttl(byte[] key) {
     Span span = helper.buildSpan("ttl", key);
-    try {
-      return super.ttl(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.ttl(key));
   }
 
   @Override
@@ -2731,14 +1551,7 @@ public Long touch(byte[]... keys) {
   public String select(int index) {
     Span span = helper.buildSpan("select");
     span.setTag("index", index);
-    try {
-      return super.select(index);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.select(index));
   }
 
   @Override
@@ -2752,56 +1565,28 @@ public String swapDB(int index1, int index2) {
   @Override
   public String flushAll() {
     Span span = helper.buildSpan("flushAll");
-    try {
-      return super.flushAll();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.flushAll());
   }
 
   @Override
   public byte[] getSet(byte[] key, byte[] value) {
     Span span = helper.buildSpan("getSet", key);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.getSet(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getSet(key, value));
   }
 
   @Override
   public List mget(byte[]... keys) {
     Span span = helper.buildSpan("mget");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.mget(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.mget(keys));
   }
 
   @Override
   public Long setnx(byte[] key, byte[] value) {
     Span span = helper.buildSpan("setnx", key);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.setnx(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setnx(key, value));
   }
 
   @Override
@@ -2817,124 +1602,61 @@ public String setex(byte[] key, int seconds, byte[] value) {
     Span span = helper.buildSpan("setex", key);
     span.setTag("value", Arrays.toString(value));
     span.setTag("seconds", seconds);
-    try {
-      return super.setex(key, seconds, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setex(key, seconds, value));
   }
 
   @Override
   public String mset(byte[]... keysvalues) {
     Span span = helper.buildSpan("mset");
     span.setTag("keysvalues", TracingHelper.toString(keysvalues));
-    try {
-      return super.mset(keysvalues);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.mset(keysvalues));
   }
 
   @Override
   public Long msetnx(byte[]... keysvalues) {
     Span span = helper.buildSpan("msetnx");
     span.setTag("keysvalues", TracingHelper.toString(keysvalues));
-    try {
-      return super.msetnx(keysvalues);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.msetnx(keysvalues));
   }
 
   @Override
   public Long decrBy(byte[] key, long integer) {
     Span span = helper.buildSpan("decrBy", key);
     span.setTag("integer", integer);
-    try {
-      return super.decrBy(key, integer);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.decrBy(key, integer));
   }
 
   @Override
   public Long decr(byte[] key) {
     Span span = helper.buildSpan("decr", key);
-    try {
-      return super.decr(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.decr(key));
   }
 
   @Override
   public Long incrBy(byte[] key, long integer) {
     Span span = helper.buildSpan("incrBy", key);
     span.setTag("integer", integer);
-    try {
-      return super.incrBy(key, integer);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.incrBy(key, integer));
   }
 
   @Override
   public Double incrByFloat(byte[] key, double integer) {
     Span span = helper.buildSpan("incrByFloat", key);
     span.setTag("integer", integer);
-    try {
-      return super.incrByFloat(key, integer);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.incrByFloat(key, integer));
   }
 
   @Override
   public Long incr(byte[] key) {
     Span span = helper.buildSpan("incr", key);
-    try {
-      return super.incr(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.incr(key));
   }
 
   @Override
   public Long append(byte[] key, byte[] value) {
     Span span = helper.buildSpan("append", key);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.append(key, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.append(key, value));
   }
 
   @Override
@@ -2942,14 +1664,7 @@ public byte[] substr(byte[] key, int start, int end) {
     Span span = helper.buildSpan("substr", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.substr(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.substr(key, start, end));
   }
 
   @Override
@@ -2957,14 +1672,7 @@ public Long hset(byte[] key, byte[] field, byte[] value) {
     Span span = helper.buildSpan("hset", key);
     span.setTag("field", Arrays.toString(field));
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.hset(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hset(key, field, value));
   }
 
   @Override
@@ -2978,14 +1686,7 @@ public Long hset(byte[] key, Map hash) {
   public byte[] hget(byte[] key, byte[] field) {
     Span span = helper.buildSpan("hget", key);
     span.setTag("field", Arrays.toString(field));
-    try {
-      return super.hget(key, field);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hget(key, field));
   }
 
   @Override
@@ -2993,42 +1694,21 @@ public Long hsetnx(byte[] key, byte[] field, byte[] value) {
     Span span = helper.buildSpan("hsetnx", key);
     span.setTag("field", Arrays.toString(field));
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.hsetnx(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hsetnx(key, field, value));
   }
 
   @Override
   public String hmset(byte[] key, Map hash) {
     Span span = helper.buildSpan("hmset", key);
     span.setTag("hash", TracingHelper.toStringMap(hash));
-    try {
-      return super.hmset(key, hash);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hmset(key, hash));
   }
 
   @Override
   public List hmget(byte[] key, byte[]... fields) {
     Span span = helper.buildSpan("hmget", key);
     span.setTag("fields", TracingHelper.toString(fields));
-    try {
-      return super.hmget(key, fields);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hmget(key, fields));
   }
 
   @Override
@@ -3036,14 +1716,7 @@ public Long hincrBy(byte[] key, byte[] field, long value) {
     Span span = helper.buildSpan("hincrBy", key);
     span.setTag("field", Arrays.toString(field));
     span.setTag("value", value);
-    try {
-      return super.hincrBy(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hincrBy(key, field, value));
   }
 
   @Override
@@ -3051,135 +1724,65 @@ public Double hincrByFloat(byte[] key, byte[] field, double value) {
     Span span = helper.buildSpan("hincrByFloat", key);
     span.setTag("field", Arrays.toString(field));
     span.setTag("value", value);
-    try {
-      return super.hincrByFloat(key, field, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hincrByFloat(key, field, value));
   }
 
   @Override
   public Boolean hexists(byte[] key, byte[] field) {
     Span span = helper.buildSpan("hexists", key);
     span.setTag("field", Arrays.toString(field));
-    try {
-      return super.hexists(key, field);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hexists(key, field));
   }
 
   @Override
   public Long hdel(byte[] key, byte[]... fields) {
     Span span = helper.buildSpan("hdel", key);
     span.setTag("fields", TracingHelper.toString(fields));
-    try {
-      return super.hdel(key, fields);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hdel(key, fields));
   }
 
   @Override
   public Long hlen(byte[] key) {
     Span span = helper.buildSpan("hlen", key);
-    try {
-      return super.hlen(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hlen(key));
   }
 
   @Override
   public Set hkeys(byte[] key) {
     Span span = helper.buildSpan("hkeys", key);
-    try {
-      return super.hkeys(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hkeys(key));
   }
 
   @Override
   public Collection hvals(byte[] key) {
     Span span = helper.buildSpan("hvals", key);
-    try {
-      return super.hvals(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hvals(key));
   }
 
   @Override
   public Map hgetAll(byte[] key) {
     Span span = helper.buildSpan("hgetAll", key);
-    try {
-      return super.hgetAll(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hgetAll(key));
   }
 
   @Override
   public Long rpush(byte[] key, byte[]... strings) {
     Span span = helper.buildSpan("rpush", key);
     span.setTag("strings", TracingHelper.toString(strings));
-    try {
-      return super.rpush(key, strings);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpush(key, strings));
   }
 
   @Override
   public Long lpush(byte[] key, byte[]... strings) {
     Span span = helper.buildSpan("lpush", key);
     span.setTag("strings", TracingHelper.toString(strings));
-    try {
-      return super.lpush(key, strings);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lpush(key, strings));
   }
 
   @Override
   public Long llen(byte[] key) {
     Span span = helper.buildSpan("llen", key);
-    try {
-      return super.llen(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.llen(key));
   }
 
   @Override
@@ -3187,14 +1790,7 @@ public List lrange(byte[] key, long start, long end) {
     Span span = helper.buildSpan("lrange", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.lrange(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lrange(key, start, end));
   }
 
   @Override
@@ -3202,28 +1798,14 @@ public String ltrim(byte[] key, long start, long end) {
     Span span = helper.buildSpan("ltrim", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.ltrim(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.ltrim(key, start, end));
   }
 
   @Override
   public byte[] lindex(byte[] key, long index) {
     Span span = helper.buildSpan("lindex", key);
     span.setTag("index", index);
-    try {
-      return super.lindex(key, index);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lindex(key, index));
   }
 
   @Override
@@ -3231,14 +1813,7 @@ public String lset(byte[] key, long index, byte[] value) {
     Span span = helper.buildSpan("lset", key);
     span.setTag("index", index);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.lset(key, index, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lset(key, index, value));
   }
 
   @Override
@@ -3246,40 +1821,19 @@ public Long lrem(byte[] key, long count, byte[] value) {
     Span span = helper.buildSpan("lrem", key);
     span.setTag("count", count);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.lrem(key, count, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lrem(key, count, value));
   }
 
   @Override
   public byte[] lpop(byte[] key) {
     Span span = helper.buildSpan("lpop", key);
-    try {
-      return super.lpop(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lpop(key));
   }
 
   @Override
   public byte[] rpop(byte[] key) {
     Span span = helper.buildSpan("rpop", key);
-    try {
-      return super.rpop(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpop(key));
   }
 
   @Override
@@ -3287,82 +1841,40 @@ public byte[] rpoplpush(byte[] srckey, byte[] dstkey) {
     Span span = helper.buildSpan("rpoplpush");
     span.setTag("srckey", Arrays.toString(srckey));
     span.setTag("dstkey", Arrays.toString(dstkey));
-    try {
-      return super.rpoplpush(srckey, dstkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpoplpush(srckey, dstkey));
   }
 
   @Override
   public Long sadd(byte[] key, byte[]... members) {
     Span span = helper.buildSpan("sadd", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.sadd(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sadd(key, members));
   }
 
   @Override
   public Set smembers(byte[] key) {
     Span span = helper.buildSpan("smembers", key);
-    try {
-      return super.smembers(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.smembers(key));
   }
 
   @Override
   public Long srem(byte[] key, byte[]... member) {
     Span span = helper.buildSpan("srem", key);
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.srem(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.srem(key, member));
   }
 
   @Override
   public byte[] spop(byte[] key) {
     Span span = helper.buildSpan("spop", key);
-    try {
-      return super.spop(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.spop(key));
   }
 
   @Override
   public Set spop(byte[] key, long count) {
     Span span = helper.buildSpan("spop", key);
     span.setTag("count", count);
-    try {
-      return super.spop(key, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.spop(key, count));
   }
 
   @Override
@@ -3371,55 +1883,27 @@ public Long smove(byte[] srckey, byte[] dstkey, byte[] member) {
     span.setTag("srckey", Arrays.toString(srckey));
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.smove(srckey, dstkey, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.smove(srckey, dstkey, member));
   }
 
   @Override
   public Long scard(byte[] key) {
     Span span = helper.buildSpan("scard", key);
-    try {
-      return super.scard(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scard(key));
   }
 
   @Override
   public Boolean sismember(byte[] key, byte[] member) {
     Span span = helper.buildSpan("sismember", key);
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.sismember(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sismember(key, member));
   }
 
   @Override
   public Set sinter(byte[]... keys) {
     Span span = helper.buildSpan("sinter");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.sinter(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sinter(keys));
   }
 
   @Override
@@ -3427,28 +1911,14 @@ public Long sinterstore(byte[] dstkey, byte[]... keys) {
     Span span = helper.buildSpan("sinterstore");
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.sinterstore(dstkey, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sinterstore(dstkey, keys));
   }
 
   @Override
   public Set sunion(byte[]... keys) {
     Span span = helper.buildSpan("sunion");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.sunion(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sunion(keys));
   }
 
   @Override
@@ -3456,28 +1926,14 @@ public Long sunionstore(byte[] dstkey, byte[]... keys) {
     Span span = helper.buildSpan("sunionstore");
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.sunionstore(dstkey, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sunionstore(dstkey, keys));
   }
 
   @Override
   public Set sdiff(byte[]... keys) {
     Span span = helper.buildSpan("sdiff");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.sdiff(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sdiff(keys));
   }
 
   @Override
@@ -3485,41 +1941,20 @@ public Long sdiffstore(byte[] dstkey, byte[]... keys) {
     Span span = helper.buildSpan("sdiffstore");
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.sdiffstore(dstkey, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sdiffstore(dstkey, keys));
   }
 
   @Override
   public byte[] srandmember(byte[] key) {
     Span span = helper.buildSpan("srandmember", key);
-    try {
-      return super.srandmember(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.srandmember(key));
   }
 
   @Override
   public List srandmember(byte[] key, int count) {
     Span span = helper.buildSpan("srandmember", key);
     span.setTag("count", count);
-    try {
-      return super.srandmember(key, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.srandmember(key, count));
   }
 
   @Override
@@ -3527,14 +1962,7 @@ public Long zadd(byte[] key, double score, byte[] member) {
     Span span = helper.buildSpan("zadd", key);
     span.setTag("member", Arrays.toString(member));
     span.setTag("score", score);
-    try {
-      return super.zadd(key, score, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, score, member));
   }
 
   @Override
@@ -3543,28 +1971,14 @@ public Long zadd(byte[] key, double score, byte[] member, ZAddParams params) {
     span.setTag("member", Arrays.toString(member));
     span.setTag("score", score);
     span.setTag("params", TracingHelper.toString(params.getByteParams()));
-    try {
-      return super.zadd(key, score, member, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, score, member, params));
   }
 
   @Override
   public Long zadd(byte[] key, Map scoreMembers) {
     Span span = helper.buildSpan("zadd", key);
     span.setTag("scoreMembers", TracingHelper.toStringMap2(scoreMembers));
-    try {
-      return super.zadd(key, scoreMembers);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, scoreMembers));
   }
 
   @Override
@@ -3572,14 +1986,7 @@ public Long zadd(byte[] key, Map scoreMembers, ZAddParams params
     Span span = helper.buildSpan("zadd", key);
     span.setTag("scoreMembers", TracingHelper.toStringMap2(scoreMembers));
     span.setTag("params", TracingHelper.toString(params.getByteParams()));
-    try {
-      return super.zadd(key, scoreMembers, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zadd(key, scoreMembers, params));
   }
 
   @Override
@@ -3587,28 +1994,14 @@ public Set zrange(byte[] key, long start, long end) {
     Span span = helper.buildSpan("zrange", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrange(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrange(key, start, end));
   }
 
   @Override
   public Long zrem(byte[] key, byte[]... members) {
     Span span = helper.buildSpan("zrem", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.zrem(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrem(key, members));
   }
 
   @Override
@@ -3616,14 +2009,7 @@ public Double zincrby(byte[] key, double score, byte[] member) {
     Span span = helper.buildSpan("zincrby", key);
     span.setTag("member", Arrays.toString(member));
     span.setTag("score", score);
-    try {
-      return super.zincrby(key, score, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zincrby(key, score, member));
   }
 
   @Override
@@ -3632,42 +2018,21 @@ public Double zincrby(byte[] key, double score, byte[] member, ZIncrByParams par
     span.setTag("member", Arrays.toString(member));
     span.setTag("score", score);
     span.setTag("params", TracingHelper.toString(params.getByteParams()));
-    try {
-      return super.zincrby(key, score, member, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zincrby(key, score, member, params));
   }
 
   @Override
   public Long zrank(byte[] key, byte[] member) {
     Span span = helper.buildSpan("zrank", key);
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.zrank(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrank(key, member));
   }
 
   @Override
   public Long zrevrank(byte[] key, byte[] member) {
     Span span = helper.buildSpan("zrevrank", key);
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.zrevrank(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrank(key, member));
   }
 
   @Override
@@ -3675,14 +2040,7 @@ public Set zrevrange(byte[] key, long start, long end) {
     Span span = helper.buildSpan("zrevrange", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrevrange(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrange(key, start, end));
   }
 
   @Override
@@ -3690,14 +2048,7 @@ public Set zrangeWithScores(byte[] key, long start, long end) {
     Span span = helper.buildSpan("zrangeWithScores", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrangeWithScores(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeWithScores(key, start, end));
   }
 
   @Override
@@ -3705,85 +2056,41 @@ public Set zrevrangeWithScores(byte[] key, long start, long end) {
     Span span = helper.buildSpan("zrevrangeWithScores", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zrevrangeWithScores(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeWithScores(key, start, end));
   }
 
   @Override
   public Long zcard(byte[] key) {
     Span span = helper.buildSpan("zcard", key);
-    try {
-      return super.zcard(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zcard(key));
   }
 
   @Override
   public Double zscore(byte[] key, byte[] member) {
     Span span = helper.buildSpan("zscore", key);
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.zscore(key, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscore(key, member));
   }
 
-
   @Override
   public Long pexpireAt(String key, long millisecondsTimestamp) {
     Span span = helper.buildSpan("pexpireAt", key);
     span.setTag("millisecondsTimestamp", millisecondsTimestamp);
-    try {
-      return super.pexpireAt(key, millisecondsTimestamp);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pexpireAt(key, millisecondsTimestamp));
   }
 
   @Override
   public Long pttl(String key) {
     Span span = helper.buildSpan("pttl", key);
-    try {
-      return super.pttl(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pttl(key));
   }
 
-
   @Override
   public String psetex(String key, long milliseconds, String value) {
     Span span = helper.buildSpan("psetex", key);
     span.setTag("value", value);
     span.setTag("milliseconds", milliseconds);
-    try {
-      return super.psetex(key, milliseconds, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.psetex(key, milliseconds, value));
   }
 
   @Override
@@ -3791,86 +2098,43 @@ public String set(String key, String value, String nxxx) {
     Span span = helper.buildSpan("set", key);
     span.setTag("value", value);
     span.setTag("nxxx", nxxx);
-    try {
-      return super.set(key, value, nxxx);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.set(key, value, nxxx));
   }
 
   @Override
   public ScanResult> hscan(String key, int cursor) {
     Span span = helper.buildSpan("hscan", key);
     span.setTag("cursor", cursor);
-    try {
-      return super.hscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hscan(key, cursor));
   }
 
   @Override
   public ScanResult sscan(String key, int cursor) {
     Span span = helper.buildSpan("sscan", key);
     span.setTag("cursor", cursor);
-    try {
-      return super.sscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sscan(key, cursor));
   }
 
   @Override
   public ScanResult zscan(String key, int cursor) {
     Span span = helper.buildSpan("zscan", key);
     span.setTag("cursor", cursor);
-    try {
-      return super.zscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscan(key, cursor));
   }
 
-
   @Override
   public ScanResult scan(String cursor, ScanParams params) {
     Span span = helper.buildSpan("scan");
     span.setTag("cursor", cursor);
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.scan(cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scan(cursor, params));
   }
 
   @Override
   public ScanResult> hscan(String key, String cursor) {
     Span span = helper.buildSpan("hscan", key);
     span.setTag("cursor", cursor);
-    try {
-      return super.hscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hscan(key, cursor));
   }
 
   @Override
@@ -3878,28 +2142,14 @@ public ScanResult> hscan(String key, String cursor, ScanPa
     Span span = helper.buildSpan("hscan", key);
     span.setTag("cursor", cursor);
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.hscan(key, cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hscan(key, cursor, params));
   }
 
   @Override
   public ScanResult sscan(String key, String cursor) {
     Span span = helper.buildSpan("sscan", key);
     span.setTag("cursor", cursor);
-    try {
-      return super.sscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sscan(key, cursor));
   }
 
   @Override
@@ -3907,28 +2157,14 @@ public ScanResult sscan(String key, String cursor, ScanParams params) {
     Span span = helper.buildSpan("sscan", key);
     span.setTag("cursor", cursor);
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.sscan(key, cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sscan(key, cursor, params));
   }
 
   @Override
   public ScanResult zscan(String key, String cursor) {
     Span span = helper.buildSpan("zscan", key);
     span.setTag("cursor", cursor);
-    try {
-      return super.zscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscan(key, cursor));
   }
 
   @Override
@@ -3936,17 +2172,9 @@ public ScanResult zscan(String key, String cursor, ScanParams params) {
     Span span = helper.buildSpan("zscan", key);
     span.setTag("cursor", cursor);
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.zscan(key, cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscan(key, cursor, params));
   }
 
-
   @Override
   public void close() throws IOException {
     super.close();
@@ -3955,14 +2183,7 @@ public void close() throws IOException {
   @Override
   public Map getClusterNodes() {
     Span span = helper.buildSpan("getClusterNodes");
-    try {
-      return super.getClusterNodes();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getClusterNodes());
   }
 
   @Override
@@ -3974,28 +2195,14 @@ public Jedis getConnectionFromSlot(int slot) {
   @Override
   public List sort(byte[] key) {
     Span span = helper.buildSpan("sort", key);
-    try {
-      return super.sort(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key));
   }
 
   @Override
   public List sort(byte[] key, SortingParams sortingParameters) {
     Span span = helper.buildSpan("sort", key);
     span.setTag("sortingParameters", TracingHelper.toString(sortingParameters.getParams()));
-    try {
-      return super.sort(key, sortingParameters);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key, sortingParameters));
   }
 
   @Override
@@ -4003,14 +2210,7 @@ public List blpop(int timeout, byte[]... keys) {
     Span span = helper.buildSpan("blpop");
     span.setTag("timeout", timeout);
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.blpop(timeout, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.blpop(timeout, keys));
   }
 
   @Override
@@ -4018,28 +2218,14 @@ public Long sort(byte[] key, SortingParams sortingParameters, byte[] dstkey) {
     Span span = helper.buildSpan("sort", key);
     span.setTag("sortingParameters", TracingHelper.toString(sortingParameters.getParams()));
     span.setTag("dstkey", Arrays.toString(dstkey));
-    try {
-      return super.sort(key, sortingParameters, dstkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key, sortingParameters, dstkey));
   }
 
   @Override
   public Long sort(byte[] key, byte[] dstkey) {
     Span span = helper.buildSpan("sort", key);
     span.setTag("dstkey", Arrays.toString(dstkey));
-    try {
-      return super.sort(key, dstkey);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sort(key, dstkey));
   }
 
   @Override
@@ -4047,44 +2233,21 @@ public List brpop(int timeout, byte[]... keys) {
     Span span = helper.buildSpan("brpop");
     span.setTag("timeout", timeout);
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.brpop(timeout, keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.brpop(timeout, keys));
   }
 
-
   @Override
   public String auth(String password) {
     Span span = helper.buildSpan("auth");
-    try {
-      return super.auth(password);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.auth(password));
   }
 
-
   @Override
   public Long zcount(byte[] key, double min, double max) {
     Span span = helper.buildSpan("zcount", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zcount(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zcount(key, min, max));
   }
 
   @Override
@@ -4092,14 +2255,7 @@ public Long zcount(byte[] key, byte[] min, byte[] max) {
     Span span = helper.buildSpan("zcount", key);
     span.setTag("min", Arrays.toString(min));
     span.setTag("max", Arrays.toString(max));
-    try {
-      return super.zcount(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zcount(key, min, max));
   }
 
   @Override
@@ -4107,14 +2263,7 @@ public Set zrangeByScore(byte[] key, double min, double max) {
     Span span = helper.buildSpan("zrangeByScore", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByScore(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max));
   }
 
   @Override
@@ -4122,14 +2271,7 @@ public Set zrangeByScore(byte[] key, byte[] min, byte[] max) {
     Span span = helper.buildSpan("zrangeByScore", key);
     span.setTag("min", Arrays.toString(min));
     span.setTag("max", Arrays.toString(max));
-    try {
-      return super.zrangeByScore(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max));
   }
 
   @Override
@@ -4139,14 +2281,7 @@ public Set zrangeByScore(byte[] key, double min, double max, int offset,
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScore(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max, offset, count));
   }
 
   @Override
@@ -4156,14 +2291,7 @@ public Set zrangeByScore(byte[] key, byte[] min, byte[] max, int offset,
     span.setTag("max", Arrays.toString(max));
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScore(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScore(key, min, max, offset, count));
   }
 
   @Override
@@ -4171,14 +2299,7 @@ public Set zrangeByScoreWithScores(byte[] key, double min, double max) {
     Span span = helper.buildSpan("zrangeByScoreWithScores", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max));
   }
 
   @Override
@@ -4186,14 +2307,7 @@ public Set zrangeByScoreWithScores(byte[] key, byte[] min, byte[] max) {
     Span span = helper.buildSpan("zrangeByScoreWithScores", key);
     span.setTag("min", Arrays.toString(min));
     span.setTag("max", Arrays.toString(max));
-    try {
-      return super.zrangeByScoreWithScores(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max));
   }
 
   @Override
@@ -4204,14 +2318,7 @@ public Set zrangeByScoreWithScores(byte[] key, double min, double max, in
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max, offset, count));
   }
 
   @Override
@@ -4222,14 +2329,7 @@ public Set zrangeByScoreWithScores(byte[] key, byte[] min, byte[] max, in
     span.setTag("max", Arrays.toString(max));
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByScoreWithScores(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByScoreWithScores(key, min, max, offset, count));
   }
 
   @Override
@@ -4237,14 +2337,7 @@ public Set zrevrangeByScore(byte[] key, double max, double min) {
     Span span = helper.buildSpan("zrevrangeByScore", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrevrangeByScore(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min));
   }
 
   @Override
@@ -4252,14 +2345,7 @@ public Set zrevrangeByScore(byte[] key, byte[] max, byte[] min) {
     Span span = helper.buildSpan("zrevrangeByScore", key);
     span.setTag("max", Arrays.toString(max));
     span.setTag("min", Arrays.toString(min));
-    try {
-      return super.zrevrangeByScore(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min));
   }
 
   @Override
@@ -4269,14 +2355,7 @@ public Set zrevrangeByScore(byte[] key, double max, double min, int offs
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScore(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min, offset, count));
   }
 
   @Override
@@ -4286,14 +2365,7 @@ public Set zrevrangeByScore(byte[] key, byte[] max, byte[] min, int offs
     span.setTag("max", Arrays.toString(max));
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScore(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScore(key, max, min, offset, count));
   }
 
   @Override
@@ -4301,14 +2373,7 @@ public Set zrevrangeByScoreWithScores(byte[] key, double max, double min)
     Span span = helper.buildSpan("zrevrangeByScoreWithScores", key);
     span.setTag("min", min);
     span.setTag("max", max);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min));
   }
 
   @Override
@@ -4319,14 +2384,7 @@ public Set zrevrangeByScoreWithScores(byte[] key, double max, double min,
     span.setTag("max", max);
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min, offset, count));
   }
 
   @Override
@@ -4334,14 +2392,7 @@ public Set zrevrangeByScoreWithScores(byte[] key, byte[] max, byte[] min)
     Span span = helper.buildSpan("zrevrangeByScoreWithScores", key);
     span.setTag("max", Arrays.toString(max));
     span.setTag("min", Arrays.toString(min));
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min));
   }
 
   @Override
@@ -4352,14 +2403,7 @@ public Set zrevrangeByScoreWithScores(byte[] key, byte[] max, byte[] min,
     span.setTag("max", Arrays.toString(max));
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByScoreWithScores(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByScoreWithScores(key, max, min, offset, count));
   }
 
   @Override
@@ -4367,14 +2411,7 @@ public Long zremrangeByRank(byte[] key, long start, long end) {
     Span span = helper.buildSpan("zremrangeByRank", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zremrangeByRank(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByRank(key, start, end));
   }
 
   @Override
@@ -4382,14 +2419,7 @@ public Long zremrangeByScore(byte[] key, double start, double end) {
     Span span = helper.buildSpan("zremrangeByScore", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.zremrangeByScore(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByScore(key, start, end));
   }
 
   @Override
@@ -4397,14 +2427,7 @@ public Long zremrangeByScore(byte[] key, byte[] start, byte[] end) {
     Span span = helper.buildSpan("zremrangeByScore", key);
     span.setTag("start", Arrays.toString(start));
     span.setTag("end", Arrays.toString(end));
-    try {
-      return super.zremrangeByScore(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByScore(key, start, end));
   }
 
   @Override
@@ -4412,14 +2435,7 @@ public Long zunionstore(byte[] dstkey, byte[]... sets) {
     Span span = helper.buildSpan("zunionstore");
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("sets", TracingHelper.toString(sets));
-    try {
-      return super.zunionstore(dstkey, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zunionstore(dstkey, sets));
   }
 
   @Override
@@ -4428,14 +2444,7 @@ public Long zunionstore(byte[] dstkey, ZParams params, byte[]... sets) {
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("params", TracingHelper.toString(params.getParams()));
     span.setTag("sets", TracingHelper.toString(sets));
-    try {
-      return super.zunionstore(dstkey, params, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zunionstore(dstkey, params, sets));
   }
 
   @Override
@@ -4443,14 +2452,7 @@ public Long zinterstore(byte[] dstkey, byte[]... sets) {
     Span span = helper.buildSpan("zinterstore");
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("sets", TracingHelper.toString(sets));
-    try {
-      return super.zinterstore(dstkey, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zinterstore(dstkey, sets));
   }
 
   @Override
@@ -4459,14 +2461,7 @@ public Long zinterstore(byte[] dstkey, ZParams params, byte[]... sets) {
     span.setTag("dstkey", Arrays.toString(dstkey));
     span.setTag("params", TracingHelper.toString(params.getParams()));
     span.setTag("sets", TracingHelper.toString(sets));
-    try {
-      return super.zinterstore(dstkey, params, sets);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zinterstore(dstkey, params, sets));
   }
 
   @Override
@@ -4474,14 +2469,7 @@ public Long zlexcount(byte[] key, byte[] min, byte[] max) {
     Span span = helper.buildSpan("zlexcount");
     span.setTag("min", Arrays.toString(min));
     span.setTag("max", Arrays.toString(max));
-    try {
-      return super.zlexcount(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zlexcount(key, min, max));
   }
 
   @Override
@@ -4489,14 +2477,7 @@ public Set zrangeByLex(byte[] key, byte[] min, byte[] max) {
     Span span = helper.buildSpan("zrangeByLex", key);
     span.setTag("min", Arrays.toString(min));
     span.setTag("max", Arrays.toString(max));
-    try {
-      return super.zrangeByLex(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByLex(key, min, max));
   }
 
   @Override
@@ -4506,14 +2487,7 @@ public Set zrangeByLex(byte[] key, byte[] min, byte[] max, int offset, i
     span.setTag("max", Arrays.toString(max));
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrangeByLex(key, min, max, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrangeByLex(key, min, max, offset, count));
   }
 
   @Override
@@ -4521,14 +2495,7 @@ public Set zrevrangeByLex(byte[] key, byte[] max, byte[] min) {
     Span span = helper.buildSpan("zrevrangeByLex", key);
     span.setTag("max", Arrays.toString(max));
     span.setTag("min", Arrays.toString(min));
-    try {
-      return super.zrevrangeByLex(key, max, min);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByLex(key, max, min));
   }
 
   @Override
@@ -4538,14 +2505,7 @@ public Set zrevrangeByLex(byte[] key, byte[] max, byte[] min, int offset
     span.setTag("max", Arrays.toString(max));
     span.setTag("offset", offset);
     span.setTag("count", count);
-    try {
-      return super.zrevrangeByLex(key, max, min, offset, count);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zrevrangeByLex(key, max, min, offset, count));
   }
 
   @Override
@@ -4553,149 +2513,70 @@ public Long zremrangeByLex(byte[] key, byte[] min, byte[] max) {
     Span span = helper.buildSpan("zremrangeByLex", key);
     span.setTag("min", Arrays.toString(min));
     span.setTag("max", Arrays.toString(max));
-    try {
-      return super.zremrangeByLex(key, min, max);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zremrangeByLex(key, min, max));
   }
 
   @Override
   public String save() {
     Span span = helper.buildSpan("save");
-    try {
-      return super.save();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.save());
   }
 
   @Override
   public String bgsave() {
     Span span = helper.buildSpan("bgsave");
-    try {
-      return super.bgsave();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bgsave());
   }
 
   @Override
   public String bgrewriteaof() {
     Span span = helper.buildSpan("bgrewriteaof");
-    try {
-      return super.bgrewriteaof();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bgrewriteaof());
   }
 
   @Override
   public Long lastsave() {
     Span span = helper.buildSpan("lastsave");
-    try {
-      return super.lastsave();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lastsave());
   }
 
   @Override
   public String shutdown() {
     Span span = helper.buildSpan("shutdown");
-    try {
-      return super.shutdown();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.shutdown());
   }
 
   @Override
   public String info() {
     Span span = helper.buildSpan("info");
-    try {
-      return super.info();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.info());
   }
 
   @Override
   public String info(String section) {
     Span span = helper.buildSpan("info");
     span.setTag("section", section);
-    try {
-      return super.info(section);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.info(section));
   }
 
-
   @Override
   public String slaveof(String host, int port) {
     Span span = helper.buildSpan("slaveof");
     span.setTag("host", host);
     span.setTag("port", port);
-    try {
-      return super.slaveof(host, port);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.slaveof(host, port));
   }
 
   @Override
   public String slaveofNoOne() {
     Span span = helper.buildSpan("slaveofNoOne");
-    try {
-      return super.slaveofNoOne();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.slaveofNoOne());
   }
 
-
   @Override
   public String configResetStat() {
     Span span = helper.buildSpan("configResetStat");
-    try {
-      return super.configResetStat();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.configResetStat());
   }
 
   @Override
@@ -4704,74 +2585,37 @@ public String configRewrite() {
     return helper.decorate(span, super::configRewrite);
   }
 
-
   @Override
   public Long strlen(byte[] key) {
     Span span = helper.buildSpan("strlen", key);
-    try {
-      return super.strlen(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.strlen(key));
   }
 
-
   @Override
   public Long lpushx(byte[] key, byte[]... string) {
     Span span = helper.buildSpan("lpushx", key);
     span.setTag("string", TracingHelper.toString(string));
-    try {
-      return super.lpushx(key, string);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.lpushx(key, string));
   }
 
   @Override
   public Long persist(byte[] key) {
     Span span = helper.buildSpan("persist", key);
-    try {
-      return super.persist(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.persist(key));
   }
 
   @Override
   public Long rpushx(byte[] key, byte[]... string) {
     Span span = helper.buildSpan("rpushx", key);
     span.setTag("string", TracingHelper.toString(string));
-    try {
-      return super.rpushx(key, string);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.rpushx(key, string));
   }
 
   @Override
   public byte[] echo(byte[] string) {
     Span span = helper.buildSpan("echo");
     span.setTag("string", Arrays.toString(string));
-    try {
-      return super.echo(string);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.echo(string));
   }
 
   @Override
@@ -4780,14 +2624,7 @@ public Long linsert(byte[] key, LIST_POSITION where, byte[] pivot, byte[] value)
     span.setTag("where", where.name());
     span.setTag("pivot", Arrays.toString(pivot));
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.linsert(key, where, pivot, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.linsert(key, where, pivot, value));
   }
 
   @Override
@@ -4803,31 +2640,16 @@ public Long linsert(byte[] key, ListPosition where, byte[] pivot, byte[] value)
   public String debug(DebugParams params) {
     Span span = helper.buildSpan("debug");
     span.setTag("params", Arrays.toString(params.getCommand()));
-    try {
-      return super.debug(params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.debug(params));
   }
 
-
   @Override
   public byte[] brpoplpush(byte[] source, byte[] destination, int timeout) {
     Span span = helper.buildSpan("brpoplpush");
     span.setTag("timeout", timeout);
     span.setTag("source", Arrays.toString(source));
     span.setTag("destination", Arrays.toString(destination));
-    try {
-      return super.brpoplpush(source, destination, timeout);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.brpoplpush(source, destination, timeout));
   }
 
   @Override
@@ -4835,14 +2657,7 @@ public Boolean setbit(byte[] key, long offset, boolean value) {
     Span span = helper.buildSpan("setbit", key);
     span.setTag("offset", offset);
     span.setTag("value", value);
-    try {
-      return super.setbit(key, offset, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setbit(key, offset, value));
   }
 
   @Override
@@ -4850,44 +2665,22 @@ public Boolean setbit(byte[] key, long offset, byte[] value) {
     Span span = helper.buildSpan("setbit", key);
     span.setTag("offset", offset);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.setbit(key, offset, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setbit(key, offset, value));
   }
 
   @Override
   public Boolean getbit(byte[] key, long offset) {
     Span span = helper.buildSpan("getbit", key);
     span.setTag("offset", offset);
-    try {
-      return super.getbit(key, offset);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getbit(key, offset));
   }
 
-
   @Override
   public Long setrange(byte[] key, long offset, byte[] value) {
     Span span = helper.buildSpan("setrange", key);
     span.setTag("offset", offset);
     span.setTag("value", Arrays.toString(value));
-    try {
-      return super.setrange(key, offset, value);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.setrange(key, offset, value));
   }
 
   @Override
@@ -4895,14 +2688,7 @@ public byte[] getrange(byte[] key, long startOffset, long endOffset) {
     Span span = helper.buildSpan("getrange", key);
     span.setTag("startOffset", startOffset);
     span.setTag("endOffset", endOffset);
-    try {
-      return super.getrange(key, startOffset, endOffset);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getrange(key, startOffset, endOffset));
   }
 
   @Override
@@ -4910,55 +2696,27 @@ public Long publish(byte[] channel, byte[] message) {
     Span span = helper.buildSpan("publish");
     span.setTag("channel", Arrays.toString(channel));
     span.setTag("message", Arrays.toString(message));
-    try {
-      return super.publish(channel, message);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.publish(channel, message));
   }
 
   @Override
   public void subscribe(BinaryJedisPubSub jedisPubSub, byte[]... channels) {
     Span span = helper.buildSpan("subscribe");
     span.setTag("channels", Arrays.toString(channels));
-    try {
-      super.subscribe(jedisPubSub, channels);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    helper.decorate(span, () -> super.subscribe(jedisPubSub, channels));
   }
 
   @Override
   public void psubscribe(BinaryJedisPubSub jedisPubSub, byte[]... patterns) {
     Span span = helper.buildSpan("psubscribe");
     span.setTag("patterns", Arrays.toString(patterns));
-    try {
-      super.psubscribe(jedisPubSub, patterns);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    helper.decorate(span, () -> super.psubscribe(jedisPubSub, patterns));
   }
 
   @Override
   public Long getDB() {
     Span span = helper.buildSpan("getDB");
-    try {
-      return super.getDB();
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.getDB());
   }
 
   @Override
@@ -4967,42 +2725,21 @@ public Object eval(byte[] script, List keys, List args) {
     span.setTag("script", Arrays.toString(script));
     span.setTag("keys", TracingHelper.toString(keys));
     span.setTag("args", TracingHelper.toString(args));
-    try {
-      return super.eval(script, keys, args);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, keys, args));
   }
 
   @Override
   public Object eval(byte[] script, byte[] key) {
     Span span = helper.buildSpan("eval", key);
     span.setTag("script", Arrays.toString(script));
-    try {
-      return super.eval(script, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, key));
   }
 
   @Override
   public Object evalsha(byte[] script, byte[] key) {
     Span span = helper.buildSpan("evalsha", key);
     span.setTag("script", Arrays.toString(script));
-    try {
-      return super.evalsha(script, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.evalsha(script, key));
   }
 
   @Override
@@ -5011,14 +2748,7 @@ public Object eval(byte[] script, byte[] keyCount, byte[]... params) {
     span.setTag("script", Arrays.toString(script));
     span.setTag("keyCount", Arrays.toString(keyCount));
     span.setTag("params", TracingHelper.toString(params));
-    try {
-      return super.eval(script, keyCount, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, keyCount, params));
   }
 
   @Override
@@ -5027,31 +2757,16 @@ public Object eval(byte[] script, int keyCount, byte[]... params) {
     span.setTag("script", Arrays.toString(script));
     span.setTag("keyCount", keyCount);
     span.setTag("params", TracingHelper.toString(params));
-    try {
-      return super.eval(script, keyCount, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.eval(script, keyCount, params));
   }
 
-
   @Override
   public Object evalsha(byte[] sha1, List keys, List args) {
     Span span = helper.buildSpan("evalsha");
     span.setTag("sha1", Arrays.toString(sha1));
     span.setTag("keys", TracingHelper.toString(keys));
     span.setTag("args", TracingHelper.toString(args));
-    try {
-      return super.evalsha(sha1, keys, args);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.evalsha(sha1, keys, args));
   }
 
   @Override
@@ -5060,82 +2775,39 @@ public Object evalsha(byte[] sha1, int keyCount, byte[]... params) {
     span.setTag("params", TracingHelper.toString(params));
     span.setTag("sha1", Arrays.toString(sha1));
     span.setTag("keyCount", keyCount);
-    try {
-      return super.evalsha(sha1, keyCount, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.evalsha(sha1, keyCount, params));
   }
 
   @Override
   public List scriptExists(byte[] key, byte[][] sha1) {
     Span span = helper.buildSpan("scriptExists", key);
     span.setTag("sha1", TracingHelper.toString(sha1));
-    try {
-      return super.scriptExists(key, sha1);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptExists(key, sha1));
   }
 
   @Override
   public byte[] scriptLoad(byte[] script, byte[] key) {
     Span span = helper.buildSpan("scriptLoad", key);
     span.setTag("script", Arrays.toString(script));
-    try {
-      return super.scriptLoad(script, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptLoad(script, key));
   }
 
   @Override
   public String scriptFlush(byte[] key) {
     Span span = helper.buildSpan("scriptFlush", key);
-    try {
-      return super.scriptFlush(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptFlush(key));
   }
 
   @Override
   public String scriptKill(byte[] key) {
     Span span = helper.buildSpan("scriptKill", key);
-    try {
-      return super.scriptKill(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scriptKill(key));
   }
 
-
   @Override
   public Long bitcount(byte[] key) {
     Span span = helper.buildSpan("bitcount", key);
-    try {
-      return super.bitcount(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitcount(key));
   }
 
   @Override
@@ -5143,14 +2815,7 @@ public Long bitcount(byte[] key, long start, long end) {
     Span span = helper.buildSpan("bitcount", key);
     span.setTag("start", start);
     span.setTag("end", end);
-    try {
-      return super.bitcount(key, start, end);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitcount(key, start, end));
   }
 
   @Override
@@ -5158,86 +2823,42 @@ public Long bitop(BitOP op, byte[] destKey, byte[]... srcKeys) {
     Span span = helper.buildSpan("bitop");
     span.setTag("destKey", Arrays.toString(destKey));
     span.setTag("srcKeys", TracingHelper.toString(srcKeys));
-    try {
-      return super.bitop(op, destKey, srcKeys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitop(op, destKey, srcKeys));
   }
 
-
   @Override
   public Long pexpire(byte[] key, long milliseconds) {
     Span span = helper.buildSpan("pexpire", key);
     span.setTag("milliseconds", milliseconds);
-    try {
-      return super.pexpire(key, milliseconds);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pexpire(key, milliseconds));
   }
 
   @Override
   public Long pexpireAt(byte[] key, long millisecondsTimestamp) {
     Span span = helper.buildSpan("pexpireAt", key);
     span.setTag("millisecondsTimestamp", millisecondsTimestamp);
-    try {
-      return super.pexpireAt(key, millisecondsTimestamp);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pexpireAt(key, millisecondsTimestamp));
   }
 
-
   @Override
   public Long waitReplicas(int replicas, long timeout) {
     Span span = helper.buildSpan("waitReplicas");
     span.setTag("replicas", replicas);
     span.setTag("timeout", timeout);
-    try {
-      return super.waitReplicas(replicas, timeout);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.waitReplicas(replicas, timeout));
   }
 
   @Override
   public Long pfadd(byte[] key, byte[]... elements) {
     Span span = helper.buildSpan("pfadd", key);
     span.setTag("elements", TracingHelper.toString(elements));
-    try {
-      return super.pfadd(key, elements);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfadd(key, elements));
   }
 
   @Override
   public long pfcount(byte[] key) {
     Span span = helper.buildSpan("pfcount", key);
-    try {
-      return super.pfcount(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfcount(key));
   }
 
   @Override
@@ -5245,58 +2866,29 @@ public String pfmerge(byte[] destkey, byte[]... sourcekeys) {
     Span span = helper.buildSpan("pfmerge");
     span.setTag("destkey", Arrays.toString(destkey));
     span.setTag("sourcekeys", TracingHelper.toString(sourcekeys));
-    try {
-      return super.pfmerge(destkey, sourcekeys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfmerge(destkey, sourcekeys));
   }
 
   @Override
   public Long pfcount(byte[]... keys) {
     Span span = helper.buildSpan("pfcount");
     span.setTag("keys", TracingHelper.toString(keys));
-    try {
-      return super.pfcount(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfcount(keys));
   }
 
-
   @Override
   public ScanResult scan(byte[] cursor, ScanParams params) {
     Span span = helper.buildSpan("scan");
     span.setTag("cursor", Arrays.toString(cursor));
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.scan(cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.scan(cursor, params));
   }
 
   @Override
   public ScanResult> hscan(byte[] key, byte[] cursor) {
     Span span = helper.buildSpan("hscan", key);
     span.setTag("cursor", Arrays.toString(cursor));
-    try {
-      return super.hscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hscan(key, cursor));
   }
 
   @Override
@@ -5304,28 +2896,14 @@ public ScanResult> hscan(byte[] key, byte[] cursor, ScanPa
     Span span = helper.buildSpan("hscan", key);
     span.setTag("cursor", Arrays.toString(cursor));
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.hscan(key, cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.hscan(key, cursor, params));
   }
 
   @Override
   public ScanResult sscan(byte[] key, byte[] cursor) {
     Span span = helper.buildSpan("sscan", key);
     span.setTag("cursor", Arrays.toString(cursor));
-    try {
-      return super.sscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sscan(key, cursor));
   }
 
   @Override
@@ -5333,28 +2911,14 @@ public ScanResult sscan(byte[] key, byte[] cursor, ScanParams params) {
     Span span = helper.buildSpan("sscan", key);
     span.setTag("cursor", Arrays.toString(cursor));
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.sscan(key, cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.sscan(key, cursor, params));
   }
 
   @Override
   public ScanResult zscan(byte[] key, byte[] cursor) {
     Span span = helper.buildSpan("zscan", key);
     span.setTag("cursor", Arrays.toString(cursor));
-    try {
-      return super.zscan(key, cursor);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscan(key, cursor));
   }
 
   @Override
@@ -5362,14 +2926,7 @@ public ScanResult zscan(byte[] key, byte[] cursor, ScanParams params) {
     Span span = helper.buildSpan("zscan", key);
     span.setTag("cursor", Arrays.toString(cursor));
     span.setTag("params", TracingHelper.toString(params.getParams()));
-    try {
-      return super.zscan(key, cursor, params);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.zscan(key, cursor, params));
   }
 
   @Override
@@ -5400,28 +2957,14 @@ public Long geoadd(byte[] key, double longitude, double latitude, byte[] member)
     span.setTag("longitude", longitude);
     span.setTag("latitude", latitude);
     span.setTag("member", Arrays.toString(member));
-    try {
-      return super.geoadd(key, longitude, latitude, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geoadd(key, longitude, latitude, member));
   }
 
   @Override
   public Long geoadd(byte[] key, Map memberCoordinateMap) {
     Span span = helper.buildSpan("geoadd", key);
     span.setTag("memberCoordinateMap", TracingHelper.toStringMap2(memberCoordinateMap));
-    try {
-      return super.geoadd(key, memberCoordinateMap);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geoadd(key, memberCoordinateMap));
   }
 
   @Override
@@ -5429,14 +2972,7 @@ public Double geodist(byte[] key, byte[] member1, byte[] member2) {
     Span span = helper.buildSpan("geodist", key);
     span.setTag("member1", Arrays.toString(member1));
     span.setTag("member2", Arrays.toString(member2));
-    try {
-      return super.geodist(key, member1, member2);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geodist(key, member1, member2));
   }
 
   @Override
@@ -5445,42 +2981,21 @@ public Double geodist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit)
     span.setTag("member1", Arrays.toString(member1));
     span.setTag("member2", Arrays.toString(member2));
     span.setTag("unit", unit.name());
-    try {
-      return super.geodist(key, member1, member2, unit);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geodist(key, member1, member2, unit));
   }
 
   @Override
   public List geohash(byte[] key, byte[]... members) {
     Span span = helper.buildSpan("geohash", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.geohash(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geohash(key, members));
   }
 
   @Override
   public List geopos(byte[] key, byte[]... members) {
     Span span = helper.buildSpan("geopos", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.geopos(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geopos(key, members));
   }
 
   @Override
@@ -5491,14 +3006,7 @@ public List georadius(byte[] key, double longitude, double la
     span.setTag("latitude", latitude);
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
-    try {
-      return super.georadius(key, longitude, latitude, radius, unit);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadius(key, longitude, latitude, radius, unit));
   }
 
   @Override
@@ -5522,14 +3030,7 @@ public List georadius(byte[] key, double longitude, double la
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
     span.setTag("param", TracingHelper.toString(param.getByteParams()));
-    try {
-      return super.georadius(key, longitude, latitude, radius, unit, param);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadius(key, longitude, latitude, radius, unit, param));
   }
 
   @Override
@@ -5553,14 +3054,7 @@ public List georadiusByMember(byte[] key, byte[] member, doub
     span.setTag("member", Arrays.toString(member));
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
-    try {
-      return super.georadiusByMember(key, member, radius, unit);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadiusByMember(key, member, radius, unit));
   }
 
   @Override
@@ -5582,14 +3076,7 @@ public List georadiusByMember(byte[] key, byte[] member, doub
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
     span.setTag("param", TracingHelper.toString(param.getByteParams()));
-    try {
-      return super.georadiusByMember(key, member, radius, unit, param);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadiusByMember(key, member, radius, unit, param));
   }
 
   @Override
@@ -5615,40 +3102,19 @@ public Set keys(byte[] pattern) {
   public Long pfadd(String key, String... elements) {
     Span span = helper.buildSpan("pfadd");
     span.setTag("elements", Arrays.toString(elements));
-    try {
-      return super.pfadd(key, elements);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfadd(key, elements));
   }
 
   @Override
   public long pfcount(String key) {
     Span span = helper.buildSpan("pfcount", key);
-    try {
-      return super.pfcount(key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfcount(key));
   }
 
   @Override
   public long pfcount(String... keys) {
     Span span = helper.buildSpan("pfcount", keys);
-    try {
-      return super.pfcount(keys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfcount(keys));
   }
 
   @Override
@@ -5656,42 +3122,21 @@ public String pfmerge(String destkey, String... sourcekeys) {
     Span span = helper.buildSpan("pfmerge");
     span.setTag("destkey", destkey);
     span.setTag("sourcekeys", Arrays.toString(sourcekeys));
-    try {
-      return super.pfmerge(destkey, sourcekeys);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.pfmerge(destkey, sourcekeys));
   }
 
   @Override
   public List blpop(int timeout, String key) {
     Span span = helper.buildSpan("blpop");
     span.setTag("timeout", timeout);
-    try {
-      return super.blpop(timeout, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.blpop(timeout, key));
   }
 
   @Override
   public List brpop(int timeout, String key) {
     Span span = helper.buildSpan("brpop");
     span.setTag("timeout", timeout);
-    try {
-      return super.brpop(timeout, key);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.brpop(timeout, key));
   }
 
   @Override
@@ -5700,28 +3145,14 @@ public Long geoadd(String key, double longitude, double latitude, String member)
     span.setTag("longitude", longitude);
     span.setTag("latitude", latitude);
     span.setTag("member", member);
-    try {
-      return super.geoadd(key, longitude, latitude, member);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geoadd(key, longitude, latitude, member));
   }
 
   @Override
   public Long geoadd(String key, Map memberCoordinateMap) {
     Span span = helper.buildSpan("geoadd");
     span.setTag("memberCoordinateMap", TracingHelper.toString(memberCoordinateMap));
-    try {
-      return super.geoadd(key, memberCoordinateMap);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geoadd(key, memberCoordinateMap));
   }
 
   @Override
@@ -5729,14 +3160,7 @@ public Double geodist(String key, String member1, String member2) {
     Span span = helper.buildSpan("geodist", key);
     span.setTag("member1", member1);
     span.setTag("member2", member2);
-    try {
-      return super.geodist(key, member1, member2);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geodist(key, member1, member2));
   }
 
   @Override
@@ -5745,42 +3169,21 @@ public Double geodist(String key, String member1, String member2, GeoUnit unit)
     span.setTag("member1", member1);
     span.setTag("member2", member2);
     span.setTag("unit", unit.name());
-    try {
-      return super.geodist(key, member1, member2, unit);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geodist(key, member1, member2, unit));
   }
 
   @Override
   public List geohash(String key, String... members) {
     Span span = helper.buildSpan("geohash", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.geohash(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geohash(key, members));
   }
 
   @Override
   public List geopos(String key, String... members) {
     Span span = helper.buildSpan("geopos", key);
     span.setTag("members", Arrays.toString(members));
-    try {
-      return super.geopos(key, members);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.geopos(key, members));
   }
 
   @Override
@@ -5791,14 +3194,7 @@ public List georadius(String key, double longitude, double la
     span.setTag("latitude", latitude);
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
-    try {
-      return super.georadius(key, longitude, latitude, radius, unit);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadius(key, longitude, latitude, radius, unit));
   }
 
   @Override
@@ -5822,14 +3218,7 @@ public List georadius(String key, double longitude, double la
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
     span.setTag("param", TracingHelper.toString(param.getByteParams()));
-    try {
-      return super.georadius(key, longitude, latitude, radius, unit, param);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadius(key, longitude, latitude, radius, unit, param));
   }
 
   @Override
@@ -5853,14 +3242,7 @@ public List georadiusByMember(String key, String member, doub
     span.setTag("member", member);
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
-    try {
-      return super.georadiusByMember(key, member, radius, unit);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadiusByMember(key, member, radius, unit));
   }
 
   @Override
@@ -5882,14 +3264,7 @@ public List georadiusByMember(String key, String member, doub
     span.setTag("radius", radius);
     span.setTag("unit", unit.name());
     span.setTag("param", TracingHelper.toString(param.getByteParams()));
-    try {
-      return super.georadiusByMember(key, member, radius, unit, param);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.georadiusByMember(key, member, radius, unit, param));
   }
 
   @Override
@@ -5908,14 +3283,7 @@ public List georadiusByMemberReadonly(String key, String memb
   public List bitfield(String key, String... arguments) {
     Span span = helper.buildSpan("bitfield", key);
     span.setTag("arguments", Arrays.toString(arguments));
-    try {
-      return super.bitfield(key, arguments);
-    } catch (Exception e) {
-      onError(e, span);
-      throw e;
-    } finally {
-      span.finish();
-    }
+    return helper.decorate(span, () -> super.bitfield(key, arguments));
   }
 
   @Override
diff --git a/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/HostAndPortUtil.java b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/HostAndPortUtil.java
new file mode 100644
index 0000000..4a40c89
--- /dev/null
+++ b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/HostAndPortUtil.java
@@ -0,0 +1,119 @@
+package io.opentracing.contrib.redis;
+
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.Protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class HostAndPortUtil {
+    private static List redisHostAndPortList = new ArrayList();
+    private static List sentinelHostAndPortList = new ArrayList();
+    private static List clusterHostAndPortList = new ArrayList();
+
+    private static GenericContainer jedisClusterContainer = null;
+
+    private HostAndPortUtil() {
+        throw new InstantiationError("Must not instantiate this class");
+    }
+
+    static {
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT));
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 1));
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 2));
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 3));
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 4));
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 5));
+        redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 6));
+
+        sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT));
+        sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1));
+        sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2));
+        sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 3));
+//
+//        clusterHostAndPortList.add(new HostAndPort("localhost", 7379));
+//        clusterHostAndPortList.add(new HostAndPort("localhost", 7380));
+//        clusterHostAndPortList.add(new HostAndPort("localhost", 7381));
+//        clusterHostAndPortList.add(new HostAndPort("localhost", 7382));
+//        clusterHostAndPortList.add(new HostAndPort("localhost", 7383));
+//        clusterHostAndPortList.add(new HostAndPort("localhost", 7384));
+
+        String envRedisHosts = System.getProperty("redis-hosts");
+        String envSentinelHosts = System.getProperty("sentinel-hosts");
+        String envClusterHosts = System.getProperty("cluster-hosts");
+
+        redisHostAndPortList = parseHosts(envRedisHosts, redisHostAndPortList);
+        sentinelHostAndPortList = parseHosts(envSentinelHosts, sentinelHostAndPortList);
+        clusterHostAndPortList = parseHosts(envClusterHosts, clusterHostAndPortList);
+
+        List ports = new ArrayList<>();
+        ports.add("7000:7000");
+        ports.add("7001:7001");
+        ports.add("7002:7002");
+        ports.add("7003:7003");
+        ports.add("7004:7004");
+        jedisClusterContainer = new GenericContainer("grokzen/redis-cluster")
+                .withEnv("IP", "0.0.0.0")
+                .withExposedPorts(7000, 7001, 7002, 7003, 7004)
+                .waitingFor(Wait.forLogMessage("[\\w\\W]*Cluster state changed: ok[\\w\\W]*", 6));
+
+        ;
+        jedisClusterContainer.setPortBindings(ports);
+        jedisClusterContainer.start();
+
+        clusterHostAndPortList.add(new HostAndPort(jedisClusterContainer.getHost(), 7000));
+        clusterHostAndPortList.add(new HostAndPort(jedisClusterContainer.getHost(), 7001));
+        clusterHostAndPortList.add(new HostAndPort(jedisClusterContainer.getHost(), 7002));
+        clusterHostAndPortList.add(new HostAndPort(jedisClusterContainer.getHost(), 7003));
+        clusterHostAndPortList.add(new HostAndPort(jedisClusterContainer.getHost(), 7004));
+
+    }
+
+    public static List parseHosts(String envHosts,
+                                               List existingHostsAndPorts) {
+
+        if (null != envHosts && 0 < envHosts.length()) {
+
+            String[] hostDefs = envHosts.split(",");
+
+            if (null != hostDefs && 2 <= hostDefs.length) {
+
+                List envHostsAndPorts = new ArrayList(hostDefs.length);
+
+                for (String hostDef : hostDefs) {
+
+                    String[] hostAndPortParts = HostAndPort.extractParts(hostDef);
+
+                    if (null != hostAndPortParts && 2 == hostAndPortParts.length) {
+                        String host = hostAndPortParts[0];
+                        int port = Protocol.DEFAULT_PORT;
+
+                        try {
+                            port = Integer.parseInt(hostAndPortParts[1]);
+                        } catch (final NumberFormatException nfe) {
+                        }
+
+                    }
+                }
+
+                return envHostsAndPorts;
+            }
+        }
+
+        return existingHostsAndPorts;
+    }
+
+    public static List getRedisServers() {
+        return redisHostAndPortList;
+    }
+
+    public static List getSentinelServers() {
+        return sentinelHostAndPortList;
+    }
+
+    public static List getClusterServers() {
+        return clusterHostAndPortList;
+    }
+}
diff --git a/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/AllKindOfValuesCommandsTest.java b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/AllKindOfValuesCommandsTest.java
new file mode 100644
index 0000000..ac74983
--- /dev/null
+++ b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/AllKindOfValuesCommandsTest.java
@@ -0,0 +1,772 @@
+package io.opentracing.contrib.redis.jediscluster.commands;
+
+import org.junit.Test;
+import redis.clients.jedis.Protocol.Keyword;
+import redis.clients.jedis.ScanParams;
+import redis.clients.jedis.ScanResult;
+import redis.clients.jedis.exceptions.JedisDataException;
+import redis.clients.util.JedisClusterCRC16;
+import redis.clients.util.SafeEncoder;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static io.opentracing.contrib.redis.jediscluster.commands.TestKeys.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static redis.clients.jedis.ScanParams.SCAN_POINTER_START;
+import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY;
+
+public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
+    final byte[] bnx = {0x6E, 0x78};
+    final byte[] bex = {0x65, 0x78};
+    final long expireSeconds = 2;
+
+//    @Test
+//    public void ping() {
+//        String status = jedisCluster.ping();
+//        assertEquals("PONG", status);
+//    }
+
+//  @Test
+//  public void pingWithMessage() {
+//    String argument = "message";
+//    assertEquals(argument, jedis.ping(argument));
+//
+//    assertArrayEquals(bfoobar, jedis.ping(bfoobar));
+//  }
+
+    @Test
+    public void exists() {
+        String status = jedisCluster.set("foo", "bar");
+        assertEquals("OK", status);
+
+        status = jedisCluster.set(bfoo, bbar);
+        assertEquals("OK", status);
+
+        boolean reply = jedisCluster.exists("foo");
+        assertTrue(reply);
+
+        reply = jedisCluster.exists(bfoo);
+        assertTrue(reply);
+
+        long lreply = jedisCluster.del("foo");
+        assertEquals(1, lreply);
+
+        lreply = jedisCluster.del(bfoo);
+        assertEquals(1, lreply);
+
+        reply = jedisCluster.exists("foo");
+        assertFalse(reply);
+
+        reply = jedisCluster.exists(bfoo);
+        assertFalse(reply);
+    }
+
+    @Test
+    public void existsMany() {
+        String status = jedisCluster.set(foo, bar);
+        assertEquals("OK", status);
+
+        status = jedisCluster.set(foo2, bar2);
+        assertEquals("OK", status);
+
+        long reply = jedisCluster.exists(foo, foo2);
+        assertEquals(2, reply);
+
+        long lreply = jedisCluster.del(foo);
+        assertEquals(1, lreply);
+
+        reply = jedisCluster.exists(foo, foo2);
+        assertEquals(1, reply);
+    }
+
+    @Test
+    public void del() {
+        jedisCluster.set(foo, bar);
+        jedisCluster.set(foo2, bar3);
+        jedisCluster.set(foo3, bar3);
+
+        long reply = jedisCluster.del(foo, foo2, foo3);
+        assertEquals(3, reply);
+
+        Boolean breply = jedisCluster.exists(foo);
+        assertFalse(breply);
+        breply = jedisCluster.exists(foo2);
+        assertFalse(breply);
+        breply = jedisCluster.exists(foo3);
+        assertFalse(breply);
+
+        jedisCluster.set(foo, bar);
+
+        reply = jedisCluster.del(foo, foo2);
+        assertEquals(1, reply);
+
+        reply = jedisCluster.del(foo, foo2);
+        assertEquals(0, reply);
+
+        // Binary ...
+        jedisCluster.set(bfoo1, bbar1);
+        jedisCluster.set(bfoo2, bbar2);
+        jedisCluster.set(bfoo3, bbar3);
+
+        reply = jedisCluster.del(bfoo1, bfoo2, bfoo3);
+        assertEquals(3, reply);
+
+        breply = jedisCluster.exists(bfoo1);
+        assertFalse(breply);
+        breply = jedisCluster.exists(bfoo2);
+        assertFalse(breply);
+        breply = jedisCluster.exists(bfoo3);
+        assertFalse(breply);
+
+        jedisCluster.set(bfoo1, bbar1);
+
+        reply = jedisCluster.del(bfoo1, bfoo2);
+        assertEquals(1, reply);
+
+        reply = jedisCluster.del(bfoo1, bfoo2);
+        assertEquals(0, reply);
+    }
+
+    @Test
+    public void unlink() {
+        jedisCluster.set(foo1, bar1);
+        jedisCluster.set(foo2, bar2);
+        jedisCluster.set(foo3, bar3);
+
+        long reply = jedisCluster.unlink(foo1, foo2, foo3);
+        assertEquals(3, reply);
+
+        reply = jedisCluster.exists(foo1, foo2, foo3);
+        assertEquals(0, reply);
+
+        jedisCluster.set(foo1, bar1);
+
+        reply = jedisCluster.unlink(foo1, foo2);
+        assertEquals(1, reply);
+
+        reply = jedisCluster.unlink(foo1, foo2);
+        assertEquals(0, reply);
+
+        // Binary ...
+        jedisCluster.set(bfoo1, bbar1);
+        jedisCluster.set(bfoo2, bbar2);
+        jedisCluster.set(bfoo3, bbar3);
+
+        reply = jedisCluster.unlink(bfoo1, bfoo2, bfoo3);
+        assertEquals(3, reply);
+
+        reply = jedisCluster.exists(bfoo1, bfoo2, bfoo3);
+        assertEquals(0, reply);
+
+        jedisCluster.set(bfoo1, bbar1);
+
+        reply = jedisCluster.unlink(bfoo1, bfoo2);
+        assertEquals(1, reply);
+
+        reply = jedisCluster.unlink(bfoo1, bfoo2);
+        assertEquals(0, reply);
+    }
+
+    @Test
+    public void type() {
+        jedisCluster.set("foo", "bar");
+        String status = jedisCluster.type("foo");
+        assertEquals("string", status);
+
+        // Binary
+        jedisCluster.set(bfoo, bbar);
+        status = jedisCluster.type(bfoo);
+        assertEquals("string", status);
+    }
+
+    @Test
+    public void keys() {
+        jedisCluster.set(foo, bar);
+        jedisCluster.set(foobar, bar);
+
+        Set keys = jedisCluster.keys(foostar);
+        Set expected = new HashSet();
+        expected.add(foo);
+        expected.add(foobar);
+        assertEquals(expected, keys);
+
+        expected = new HashSet();
+        keys = jedisCluster.keys(barstar);
+
+        assertEquals(expected, keys);
+
+        // Binary
+        jedisCluster.set(bfoo, bbar);
+        jedisCluster.set(bfoobar, bbar);
+
+        Set bkeys = jedisCluster.keys(bfoostar);
+        assertEquals(2, bkeys.size());
+        assertTrue(setContains(bkeys, bfoo));
+        assertTrue(setContains(bkeys, bfoobar));
+
+        bkeys = jedisCluster.keys(bbarstar);
+
+        assertEquals(0, bkeys.size());
+    }
+
+//  @Test
+//  public void randomKey() {
+//    assertNull(jedis.randomKey());
+//
+//    jedis.set("foo", "bar");
+//
+//    assertEquals("foo", jedis.randomKey());
+//
+//    jedis.set("bar", "foo");
+//
+//    String randomkey = jedis.randomKey();
+//    assertTrue(randomkey.equals("foo") || randomkey.equals("bar"));
+//
+//    // Binary
+//    jedis.del("foo");
+//    jedis.del("bar");
+//    assertNull(jedis.randomKey());
+//
+//    jedis.set(bfoo, bbar);
+//
+//    assertArrayEquals(bfoo, jedis.randomBinaryKey());
+//
+//    jedis.set(bbar, bfoo);
+//
+//    byte[] randomBkey = jedis.randomBinaryKey();
+//    assertTrue(Arrays.equals(randomBkey, bfoo) || Arrays.equals(randomBkey, bbar));
+//
+//  }
+
+    @Test
+    public void rename() {
+        String key1 = "foo{rename}";
+        String key2 = "bar{rename}";
+        jedisCluster.set(key1, key2);
+        String status = jedisCluster.rename(key1, key2);
+        assertEquals("OK", status);
+
+        String value = jedisCluster.get(key1);
+        assertNull(value);
+
+        value = jedisCluster.get(key2);
+        assertEquals(key2, value);
+
+        // Binary
+        byte[] bKey1 = SafeEncoder.encode("bfoo{rename}");
+        byte[] bKey2 = SafeEncoder.encode("bbar{rename}");
+        jedisCluster.set(bKey1, bKey2);
+        String bstatus = jedisCluster.rename(bKey1, bKey2);
+        assertEquals("OK", bstatus);
+
+        byte[] bvalue = jedisCluster.get(bKey1);
+        assertNull(bvalue);
+
+        bvalue = jedisCluster.get(bKey2);
+        assertArrayEquals(bKey2, bvalue);
+    }
+
+    @Test
+    public void renameOldAndNewAreTheSame() {
+        jedisCluster.set("foo", "bar");
+        jedisCluster.rename("foo", "foo");
+
+        // Binary
+        jedisCluster.set(bfoo, bbar);
+        jedisCluster.rename(bfoo, bfoo);
+    }
+
+    @Test
+    public void renamenx() {
+        jedisCluster.set(foo, bar);
+        long status = jedisCluster.renamenx(foo, bar);
+        assertEquals(1, status);
+
+        jedisCluster.set(foo, bar);
+        status = jedisCluster.renamenx(foo, bar);
+        assertEquals(0, status);
+
+        // Binary
+        jedisCluster.set(bfoo, bbar);
+        long bstatus = jedisCluster.renamenx(bfoo, bbar);
+        assertEquals(1, bstatus);
+
+        jedisCluster.set(bfoo, bbar);
+        bstatus = jedisCluster.renamenx(bfoo, bbar);
+        assertEquals(0, bstatus);
+
+    }
+
+//  @Test
+//  public void dbSize() {
+//    long size = jedisCluster.dbSize();
+//    assertEquals(0, size);
+//
+//    jedisCluster.set("foo", "bar");
+//    size = jedisCluster.dbSize();
+//    assertEquals(1, size);
+//
+//    // Binary
+//    jedisCluster.set(bfoo, bbar);
+//    size = jedisCluster.dbSize();
+//    assertEquals(2, size);
+//  }
+
+    @Test
+    public void expire() {
+        long status = jedisCluster.expire("foo", 20);
+        assertEquals(0, status);
+
+        jedisCluster.set("foo", "bar");
+        status = jedisCluster.expire("foo", 20);
+        assertEquals(1, status);
+
+        // Binary
+        long bstatus = jedisCluster.expire(bfoo, 20);
+        assertEquals(0, bstatus);
+
+        jedisCluster.set(bfoo, bbar);
+        bstatus = jedisCluster.expire(bfoo, 20);
+        assertEquals(1, bstatus);
+
+    }
+
+    @Test
+    public void expireAt() {
+        long unixTime = (System.currentTimeMillis() / 1000L) + 20;
+
+        long status = jedisCluster.expireAt("foo", unixTime);
+        assertEquals(0, status);
+
+        jedisCluster.set("foo", "bar");
+        unixTime = (System.currentTimeMillis() / 1000L) + 20;
+        status = jedisCluster.expireAt("foo", unixTime);
+        assertEquals(1, status);
+
+        // Binary
+        long bstatus = jedisCluster.expireAt(bfoo, unixTime);
+        assertEquals(0, bstatus);
+
+        jedisCluster.set(bfoo, bbar);
+        unixTime = (System.currentTimeMillis() / 1000L) + 20;
+        bstatus = jedisCluster.expireAt(bfoo, unixTime);
+        assertEquals(1, bstatus);
+
+    }
+
+    @Test
+    public void ttl() {
+        long ttl = jedisCluster.ttl("foo");
+        assertEquals(-2, ttl);
+
+        jedisCluster.set("foo", "bar");
+        ttl = jedisCluster.ttl("foo");
+        assertEquals(-1, ttl);
+
+        jedisCluster.expire("foo", 20);
+        ttl = jedisCluster.ttl("foo");
+        assertTrue(ttl >= 0 && ttl <= 20);
+
+        // Binary
+        long bttl = jedisCluster.ttl(bfoo);
+        assertEquals(-2, bttl);
+
+        jedisCluster.set(bfoo, bbar);
+        bttl = jedisCluster.ttl(bfoo);
+        assertEquals(-1, bttl);
+
+        jedisCluster.expire(bfoo, 20);
+        bttl = jedisCluster.ttl(bfoo);
+        assertTrue(bttl >= 0 && bttl <= 20);
+
+    }
+
+
+//  @Test
+//  public void select() {
+//    jedisCluster.set("foo", "bar");
+//    String status = jedisCluster.select(1);
+//    assertEquals("OK", status);
+//    assertNull(jedisCluster.get("foo"));
+//    status = jedisCluster.select(0);
+//    assertEquals("OK", status);
+//    assertEquals("bar", jedisCluster.get("foo"));
+//    // Binary
+//    jedisCluster.set(bfoo, bbar);
+//    String bstatus = jedisCluster.select(1);
+//    assertEquals("OK", bstatus);
+//    assertNull(jedisCluster.get(bfoo));
+//    bstatus = jedisCluster.select(0);
+//    assertEquals("OK", bstatus);
+//    assertArrayEquals(bbar, jedisCluster.get(bfoo));
+//  }
+
+//    @Test
+//    public void getDB() {
+//        assertEquals(0, jedisCluster.getDB().longValue());
+//        jedisCluster.select(1);
+//        assertEquals(1, jedisCluster.getDB().longValue());
+//    }
+
+//  @Test
+//  public void move() {
+//    long status = jedis.move("foo", 1);
+//    assertEquals(0, status);
+//
+//    jedis.set("foo", "bar");
+//    status = jedis.move("foo", 1);
+//    assertEquals(1, status);
+//    assertNull(jedis.get("foo"));
+//
+//    jedis.select(1);
+//    assertEquals("bar", jedis.get("foo"));
+//
+//    // Binary
+//    jedis.select(0);
+//    long bstatus = jedis.move(bfoo, 1);
+//    assertEquals(0, bstatus);
+//
+//    jedis.set(bfoo, bbar);
+//    bstatus = jedis.move(bfoo, 1);
+//    assertEquals(1, bstatus);
+//    assertNull(jedis.get(bfoo));
+//
+//    jedis.select(1);
+//    assertArrayEquals(bbar, jedis.get(bfoo));
+//
+//  }
+//
+//  @Test
+//  public void swapDB() {
+//    jedisCluster.set("foo1", "bar1");
+//    jedisCluster.select(1);
+//    assertNull(jedisCluster.get("foo1"));
+//    jedisCluster.set("foo2", "bar2");
+//    String status = jedisCluster.swapDB(0, 1);
+//    assertEquals("OK", status);
+//    assertEquals("bar1", jedisCluster.get("foo1"));
+//    assertNull(jedisCluster.get("foo2"));
+//    jedisCluster.select(0);
+//    assertNull(jedisCluster.get("foo1"));
+//    assertEquals("bar2", jedisCluster.get("foo2"));
+//
+//    // Binary
+//    jedisCluster.set(bfoo1, bbar1);
+//    jedisCluster.select(1);
+//    assertArrayEquals(null, jedisCluster.get(bfoo1));
+//    jedisCluster.set(bfoo2, bbar2);
+//    status = jedisCluster.swapDB(0, 1);
+//    assertEquals("OK", status);
+//    assertArrayEquals(bbar1, jedisCluster.get(bfoo1));
+//    assertArrayEquals(null, jedisCluster.get(bfoo2));
+//    jedisCluster.select(0);
+//    assertArrayEquals(null, jedisCluster.get(bfoo1));
+//    assertArrayEquals(bbar2, jedisCluster.get(bfoo2));
+//  }
+
+//  @Test
+//  public void flushDB() {
+//    jedis.set("foo", "bar");
+//    assertEquals(1, jedis.dbSize().intValue());
+//    jedis.set("bar", "foo");
+//    jedis.move("bar", 1);
+//    String status = jedis.flushDB();
+//    assertEquals("OK", status);
+//    assertEquals(0, jedis.dbSize().intValue());
+//    jedis.select(1);
+//    assertEquals(1, jedis.dbSize().intValue());
+//    jedis.del("bar");
+//
+//    // Binary
+//    jedis.select(0);
+//    jedis.set(bfoo, bbar);
+//    assertEquals(1, jedis.dbSize().intValue());
+//    jedis.set(bbar, bfoo);
+//    jedis.move(bbar, 1);
+//    String bstatus = jedis.flushDB();
+//    assertEquals("OK", bstatus);
+//    assertEquals(0, jedis.dbSize().intValue());
+//    jedis.select(1);
+//    assertEquals(1, jedis.dbSize().intValue());
+//
+//  }
+
+//
+//  @Test
+//  public void flushAll() {
+//    jedis.set("foo", "bar");
+//    assertEquals(1, jedis.dbSize().intValue());
+//    jedis.set("bar", "foo");
+//    jedis.move("bar", 1);
+//    String status = jedis.flushAll();
+//    assertEquals("OK", status);
+//    assertEquals(0, jedis.dbSize().intValue());
+//    jedis.select(1);
+//    assertEquals(0, jedis.dbSize().intValue());
+//
+//    // Binary
+//    jedis.select(0);
+//    jedis.set(bfoo, bbar);
+//    assertEquals(1, jedis.dbSize().intValue());
+//    jedis.set(bbar, bfoo);
+//    jedis.move(bbar, 1);
+//    String bstatus = jedis.flushAll();
+//    assertEquals("OK", bstatus);
+//    assertEquals(0, jedis.dbSize().intValue());
+//    jedis.select(1);
+//    assertEquals(0, jedis.dbSize().intValue());
+//
+//  }
+
+    @Test
+    public void persist() {
+        jedisCluster.setex("foo", 60 * 60, "bar");
+        assertTrue(jedisCluster.ttl("foo") > 0);
+        long status = jedisCluster.persist("foo");
+        assertEquals(1, status);
+        assertEquals(-1, jedisCluster.ttl("foo").intValue());
+
+        // Binary
+        jedisCluster.setex(bfoo, 60 * 60, bbar);
+        assertTrue(jedisCluster.ttl(bfoo) > 0);
+        long bstatus = jedisCluster.persist(bfoo);
+        assertEquals(1, bstatus);
+        assertEquals(-1, jedisCluster.ttl(bfoo).intValue());
+
+    }
+
+    @Test
+    public void echo() {
+        String result = jedisCluster.echo("hello world");
+        assertEquals("hello world", result);
+
+        // Binary
+        byte[] bresult = jedisCluster.echo(SafeEncoder.encode("hello world"));
+        assertArrayEquals(SafeEncoder.encode("hello world"), bresult);
+    }
+
+    @Test
+    public void dumpAndRestore() {
+        jedisCluster.set("foo1", "bar");
+        byte[] sv = jedisCluster.dump("foo1");
+        jedisCluster.restore("foo2", 0, sv);
+        assertEquals("bar", jedisCluster.get("foo2"));
+    }
+
+    @Test
+    public void restoreReplace() {
+        // take a separate instance
+        jedisCluster.set("foo", "bar");
+
+        Map map = new HashMap();
+        map.put("a", "A");
+        map.put("b", "B");
+
+        jedisCluster.hset("from", map);
+        byte[] serialized = jedisCluster.dump("from");
+
+        try {
+            jedisCluster.restore("foo", 0, serialized);
+            fail("Simple restore on a existing key should fail");
+        } catch (JedisDataException e) {
+            // should be here
+        }
+        assertEquals("bar", jedisCluster.get("foo"));
+
+        jedisCluster.getConnectionFromSlot(JedisClusterCRC16.getSlot("foo")).restoreReplace("foo", 0, serialized);
+        assertEquals(map, jedisCluster.hgetAll("foo"));
+    }
+
+    @Test
+    public void pexpire() {
+        long status = jedisCluster.pexpire("foo", 10000);
+        assertEquals(0, status);
+
+        jedisCluster.set("foo1", "bar1");
+        status = jedisCluster.pexpire("foo1", 10000);
+        assertEquals(1, status);
+
+        jedisCluster.set("foo2", "bar2");
+        status = jedisCluster.pexpire("foo2", 200000000000L);
+        assertEquals(1, status);
+
+        long pttl = jedisCluster.pttl("foo2");
+        assertTrue(pttl > 100000000000L);
+    }
+
+    @Test
+    public void pexpireAt() {
+        long unixTime = (System.currentTimeMillis()) + 10000;
+
+        long status = jedisCluster.pexpireAt("foo", unixTime);
+        assertEquals(0, status);
+
+        jedisCluster.set("foo", "bar");
+        unixTime = (System.currentTimeMillis()) + 10000;
+        status = jedisCluster.pexpireAt("foo", unixTime);
+        assertEquals(1, status);
+    }
+
+    @Test
+    public void pttl() {
+        long pttl = jedisCluster.pttl("foo");
+        assertEquals(-2, pttl);
+
+        jedisCluster.set("foo", "bar");
+        pttl = jedisCluster.pttl("foo");
+        assertEquals(-1, pttl);
+
+        jedisCluster.pexpire("foo", 20000);
+        pttl = jedisCluster.pttl("foo");
+        assertTrue(pttl >= 0 && pttl <= 20000);
+    }
+
+    @Test
+    public void psetex() {
+        long pttl = jedisCluster.pttl("foo");
+        assertEquals(-2, pttl);
+
+        String status = jedisCluster.psetex("foo", 200000000000L, "bar");
+        assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+
+        pttl = jedisCluster.pttl("foo");
+        assertTrue(pttl > 100000000000L);
+    }
+
+//  @Test
+//  public void scan() {
+//    jedis.set("b", "b");
+//    jedis.set("a", "a");
+//
+//    ScanResult result = jedis.scan(SCAN_POINTER_START);
+//
+//    assertEquals(SCAN_POINTER_START, result.getStringCursor());
+//    assertFalse(result.getResult().isEmpty());
+//
+//    // binary
+//    ScanResult bResult = jedis.scan(SCAN_POINTER_START_BINARY);
+//
+//    assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
+//    assertFalse(bResult.getResult().isEmpty());
+//  }
+
+    @Test
+    public void scanMatch() {
+        ScanParams params = new ScanParams();
+        params.match("a{scan}*");
+
+        jedisCluster.set("b{scan{", "b");
+        jedisCluster.set("a{scan}", "a");
+        jedisCluster.set("aa{scan}", "aa");
+        ScanResult result = jedisCluster.scan(SCAN_POINTER_START, params);
+
+        assertEquals(SCAN_POINTER_START, result.getStringCursor());
+        assertFalse(result.getResult().isEmpty());
+
+        // binary
+        params = new ScanParams();
+        params.match(SafeEncoder.encode("ba{scan}*"));
+
+        jedisCluster.set(SafeEncoder.encode("ba{scan}1"), bbar);
+        jedisCluster.set(SafeEncoder.encode("ba{scan}2"), bbar);
+        jedisCluster.set(SafeEncoder.encode("ba{scan}3"), bbar);
+
+        ScanResult bResult = jedisCluster.scan(SCAN_POINTER_START_BINARY, params);
+
+        assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
+        assertFalse(bResult.getResult().isEmpty());
+    }
+
+//  @Test
+//  public void scanCount() {
+//    ScanParams params = new ScanParams();
+//    params.count(2);
+//
+//    for (int i = 0; i < 10; i++) {
+//      jedisCluster.set("a" + i, "a" + i);
+//    }
+//
+//    ScanResult result = jedisCluster.scan(SCAN_POINTER_START, params);
+//
+//    assertFalse(result.getResult().isEmpty());
+//
+//    // binary
+//    params = new ScanParams();
+//    params.count(2);
+//
+//    jedisCluster.set(bfoo1, bbar);
+//    jedisCluster.set(bfoo2, bbar);
+//    jedisCluster.set(bfoo3, bbar);
+//
+//    ScanResult bResult = jedisCluster.scan(SCAN_POINTER_START_BINARY, params);
+//
+//    assertFalse(bResult.getResult().isEmpty());
+//  }
+//
+//  @Test
+//  public void scanIsCompleteIteration() {
+//    for (int i = 0; i < 100; i++) {
+//      jedis.set("a" + i, "a" + i);
+//    }
+//
+//    ScanResult result = jedis.scan(SCAN_POINTER_START);
+//    // note: in theory Redis would be allowed to already return all results on the 1st scan,
+//    // but in practice this never happens for data sets greater than a few tens
+//    // see: https://redis.io/commands/scan#number-of-elements-returned-at-every-scan-call
+//    assertFalse(result.isCompleteIteration());
+//
+//    result = scanCompletely(result.getStringCursor());
+//
+//    assertNotNull(result);
+//    assertTrue(result.isCompleteIteration());
+//  }
+
+//  private ScanResult scanCompletely(String cursor) {
+//    ScanResult scanResult;
+//    do {
+//      scanResult = jedis.scan(cursor);
+//      cursor = scanResult.getStringCursor();
+//    } while (!SCAN_POINTER_START.equals(scanResult.getStringCursor()));
+//
+//    return scanResult;
+//  }
+
+    @Test
+    public void setNxExAndGet() {
+        String status = jedisCluster.set("hello", "world", "NX", "EX", expireSeconds);
+        assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+        String value = jedisCluster.get("hello");
+        assertEquals("world", value);
+
+        jedisCluster.set("hello", "bar", "NX", "EX", expireSeconds);
+        value = jedisCluster.get("hello");
+        assertEquals("world", value);
+
+        long ttl = jedisCluster.ttl("hello");
+        assertTrue(ttl > 0 && ttl <= expireSeconds);
+
+        // binary
+        byte[] bworld = {0x77, 0x6F, 0x72, 0x6C, 0x64};
+        byte[] bhello = {0x68, 0x65, 0x6C, 0x6C, 0x6F};
+        String bstatus = jedisCluster.set(bworld, bhello, bnx, bex, expireSeconds);
+        assertTrue(Keyword.OK.name().equalsIgnoreCase(bstatus));
+        byte[] bvalue = jedisCluster.get(bworld);
+        assertTrue(Arrays.equals(bhello, bvalue));
+
+        jedisCluster.set(bworld, bbar, bnx, bex, expireSeconds);
+        bvalue = jedisCluster.get(bworld);
+        assertTrue(Arrays.equals(bhello, bvalue));
+
+        long bttl = jedisCluster.ttl(bworld);
+        assertTrue(bttl > 0 && bttl <= expireSeconds);
+    }
+}
diff --git a/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/BinaryValuesCommandsTest.java b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/BinaryValuesCommandsTest.java
new file mode 100644
index 0000000..5408276
--- /dev/null
+++ b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/BinaryValuesCommandsTest.java
@@ -0,0 +1,281 @@
+package io.opentracing.contrib.redis.jediscluster.commands;
+
+import org.junit.Before;
+import org.junit.Test;
+import redis.clients.jedis.Protocol.Keyword;
+import redis.clients.jedis.exceptions.JedisDataException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static io.opentracing.contrib.redis.jediscluster.commands.TestKeys.*;
+import static io.opentracing.contrib.redis.utils.AssertUtil.assertByteArrayListEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class BinaryValuesCommandsTest extends JedisCommandTestBase {
+  byte[] bxx = { 0x78, 0x78 };
+  byte[] bnx = { 0x6E, 0x78 };
+  byte[] bex = { 0x65, 0x78 };
+  byte[] bpx = { 0x70, 0x78 };
+  long expireSeconds = 2;
+  long expireMillis = expireSeconds * 1000;
+  byte[] binaryValue;
+
+  @Before
+  public void startUp() {
+    StringBuilder sb = new StringBuilder();
+
+    for (int n = 0; n < 1000; n++) {
+      sb.append("A");
+    }
+
+    binaryValue = sb.toString().getBytes();
+  }
+
+  @Test
+  public void setAndGet() {
+    String status = jedisCluster.set(bfoo, binaryValue);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+
+    byte[] value = jedisCluster.get(bfoo);
+    assertTrue(Arrays.equals(binaryValue, value));
+
+    assertNull(jedisCluster.get(bbar));
+  }
+
+  @Test
+  public void setNxExAndGet() {
+    String status = jedisCluster.set(bfoo, binaryValue, bnx, bex, expireSeconds);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+    byte[] value = jedisCluster.get(bfoo);
+    assertTrue(Arrays.equals(binaryValue, value));
+
+    assertNull(jedisCluster.get(bbar));
+  }
+
+  @Test
+  public void setIfNotExistAndGet() {
+    String status = jedisCluster.set(bfoo, binaryValue);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+    // nx should fail if value exists
+    String statusFail = jedisCluster.set(bfoo, binaryValue, bnx, bex, expireSeconds);
+    assertNull(statusFail);
+
+    byte[] value = jedisCluster.get(bfoo);
+    assertTrue(Arrays.equals(binaryValue, value));
+
+    assertNull(jedisCluster.get(bbar));
+  }
+
+  @Test
+  public void setIfExistAndGet() {
+    String status = jedisCluster.set(bfoo, binaryValue);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+    // nx should fail if value exists
+    String statusSuccess = jedisCluster.set(bfoo, binaryValue, bxx, bex, expireSeconds);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(statusSuccess));
+
+    byte[] value = jedisCluster.get(bfoo);
+    assertTrue(Arrays.equals(binaryValue, value));
+
+    assertNull(jedisCluster.get(bbar));
+  }
+
+  @Test
+  public void setFailIfNotExistAndGet() {
+    // xx should fail if value does NOT exists
+    String statusFail = jedisCluster.set(bfoo, binaryValue, bxx, bex, expireSeconds);
+    assertNull(statusFail);
+  }
+
+  @Test
+  public void setAndExpireMillis() {
+    String status = jedisCluster.set(bfoo, binaryValue, bnx, bpx, expireMillis);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+    long ttl = jedisCluster.ttl(bfoo);
+    assertTrue(ttl > 0 && ttl <= expireSeconds);
+  }
+
+  @Test
+  public void setAndExpire() {
+    String status = jedisCluster.set(bfoo, binaryValue, bnx, bex, expireSeconds);
+    assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
+    long ttl = jedisCluster.ttl(bfoo);
+    assertTrue(ttl > 0 && ttl <= expireSeconds);
+  }
+
+  @Test
+  public void getSet() {
+    byte[] value = jedisCluster.getSet(bfoo, binaryValue);
+    assertNull(value);
+    value = jedisCluster.get(bfoo);
+    assertTrue(Arrays.equals(binaryValue, value));
+  }
+
+  @Test
+  public void mget() {
+    List values = jedisCluster.mget(bfoo, bbar);
+    List expected = new ArrayList();
+    expected.add(null);
+    expected.add(null);
+
+    assertByteArrayListEquals(expected, values);
+
+    jedisCluster.set(bfoo, binaryValue);
+
+    expected = new ArrayList();
+    expected.add(binaryValue);
+    expected.add(null);
+    values = jedisCluster.mget(bfoo, bbar);
+
+    assertByteArrayListEquals(expected, values);
+
+    jedisCluster.set(bbar, bfoo);
+
+    expected = new ArrayList();
+    expected.add(binaryValue);
+    expected.add(bfoo);
+    values = jedisCluster.mget(bfoo, bbar);
+
+    assertByteArrayListEquals(expected, values);
+  }
+
+  @Test
+  public void setnx() {
+    long status = jedisCluster.setnx(bfoo, binaryValue);
+    assertEquals(1, status);
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.get(bfoo)));
+
+    status = jedisCluster.setnx(bfoo, bbar);
+    assertEquals(0, status);
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.get(bfoo)));
+  }
+
+  @Test
+  public void setex() {
+    String status = jedisCluster.setex(bfoo, 20, binaryValue);
+    assertEquals(Keyword.OK.name(), status);
+    long ttl = jedisCluster.ttl(bfoo);
+    assertTrue(ttl > 0 && ttl <= 20);
+  }
+
+  @Test
+  public void mset() {
+    String status = jedisCluster.mset(bfoo, binaryValue, bbar, bfoo);
+    assertEquals(Keyword.OK.name(), status);
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.get(bfoo)));
+    assertTrue(Arrays.equals(bfoo, jedisCluster.get(bbar)));
+  }
+
+  @Test
+  public void msetnx() {
+    long status = jedisCluster.msetnx(bfoo, binaryValue, bbar, bfoo);
+    assertEquals(1, status);
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.get(bfoo)));
+    assertTrue(Arrays.equals(bfoo, jedisCluster.get(bbar)));
+
+    status = jedisCluster.msetnx(bfoo, bbar, bbar2, "foo2".getBytes());
+    assertEquals(0, status);
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.get(bfoo)));
+    assertTrue(Arrays.equals(bfoo, jedisCluster.get(bbar)));
+  }
+
+  @Test(expected = JedisDataException.class)
+  public void incrWrongValue() {
+    jedisCluster.set(bfoo, binaryValue);
+    jedisCluster.incr(bfoo);
+  }
+
+  @Test
+  public void incr() {
+    long value = jedisCluster.incr(bfoo);
+    assertEquals(1, value);
+    value = jedisCluster.incr(bfoo);
+    assertEquals(2, value);
+  }
+
+  @Test(expected = JedisDataException.class)
+  public void incrByWrongValue() {
+    jedisCluster.set(bfoo, binaryValue);
+    jedisCluster.incrBy(bfoo, 2);
+  }
+
+  @Test
+  public void incrBy() {
+    long value = jedisCluster.incrBy(bfoo, 2);
+    assertEquals(2, value);
+    value = jedisCluster.incrBy(bfoo, 2);
+    assertEquals(4, value);
+  }
+
+  @Test(expected = JedisDataException.class)
+  public void decrWrongValue() {
+    jedisCluster.set(bfoo, binaryValue);
+    jedisCluster.decr(bfoo);
+  }
+
+  @Test
+  public void decr() {
+    long value = jedisCluster.decr(bfoo);
+    assertEquals(-1, value);
+    value = jedisCluster.decr(bfoo);
+    assertEquals(-2, value);
+  }
+
+  @Test(expected = JedisDataException.class)
+  public void decrByWrongValue() {
+    jedisCluster.set(bfoo, binaryValue);
+    jedisCluster.decrBy(bfoo, 2);
+  }
+
+  @Test
+  public void decrBy() {
+    long value = jedisCluster.decrBy(bfoo, 2);
+    assertEquals(-2, value);
+    value = jedisCluster.decrBy(bfoo, 2);
+    assertEquals(-4, value);
+  }
+
+  @Test
+  public void append() {
+    byte[] first512 = new byte[512];
+    System.arraycopy(binaryValue, 0, first512, 0, 512);
+    long value = jedisCluster.append(bfoo, first512);
+    assertEquals(512, value);
+    assertTrue(Arrays.equals(first512, jedisCluster.get(bfoo)));
+
+    byte[] rest = new byte[binaryValue.length - 512];
+    System.arraycopy(binaryValue, 512, rest, 0, binaryValue.length - 512);
+    value = jedisCluster.append(bfoo, rest);
+    assertEquals(binaryValue.length, value);
+
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.get(bfoo)));
+  }
+
+  @Test
+  public void substr() {
+    jedisCluster.set(bfoo, binaryValue);
+
+    byte[] first512 = new byte[512];
+    System.arraycopy(binaryValue, 0, first512, 0, 512);
+    byte[] rfirst512 = jedisCluster.substr(bfoo, 0, 511);
+    assertTrue(Arrays.equals(first512, rfirst512));
+
+    byte[] last512 = new byte[512];
+    System.arraycopy(binaryValue, binaryValue.length - 512, last512, 0, 512);
+    assertTrue(Arrays.equals(last512, jedisCluster.substr(bfoo, -512, -1)));
+
+    assertTrue(Arrays.equals(binaryValue, jedisCluster.substr(bfoo, 0, -1)));
+
+    assertTrue(Arrays.equals(last512, jedisCluster.substr(bfoo, binaryValue.length - 512, 100000)));
+  }
+
+  @Test
+  public void strlen() {
+    jedisCluster.set(bfoo, binaryValue);
+    assertEquals(binaryValue.length, jedisCluster.strlen(bfoo).intValue());
+  }
+}
\ No newline at end of file
diff --git a/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/BitCommandsTest.java b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/BitCommandsTest.java
new file mode 100644
index 0000000..71bb241
--- /dev/null
+++ b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/BitCommandsTest.java
@@ -0,0 +1,211 @@
+package io.opentracing.contrib.redis.jediscluster.commands;
+
+import org.junit.Test;
+import redis.clients.jedis.BitOP;
+import redis.clients.jedis.BitPosParams;
+import redis.clients.jedis.Protocol;
+import redis.clients.util.SafeEncoder;
+
+import java.util.List;
+
+import static io.opentracing.contrib.redis.jediscluster.commands.TestKeys.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class BitCommandsTest extends JedisCommandTestBase {
+  @Test
+  public void setAndgetbit() {
+    boolean bit = jedisCluster.setbit("foo", 0, true);
+    assertEquals(false, bit);
+
+    bit = jedisCluster.getbit("foo", 0);
+    assertEquals(true, bit);
+
+    boolean bbit = jedisCluster.setbit("bfoo".getBytes(), 0, "1".getBytes());
+    assertFalse(bbit);
+
+    bbit = jedisCluster.getbit("bfoo".getBytes(), 0);
+    assertTrue(bbit);
+  }
+
+  @Test
+  public void bitpos() {
+    String foo = "foo";
+
+    jedisCluster.set(foo, String.valueOf(0));
+
+    jedisCluster.setbit(foo, 3, true);
+    jedisCluster.setbit(foo, 7, true);
+    jedisCluster.setbit(foo, 13, true);
+    jedisCluster.setbit(foo, 39, true);
+
+    /*
+     * byte: 0 1 2 3 4 bit: 00010001 / 00000100 / 00000000 / 00000000 / 00000001
+     */
+    long offset = jedisCluster.bitpos(foo, true);
+    assertEquals(2, offset);
+    offset = jedisCluster.bitpos(foo, false);
+    assertEquals(0, offset);
+
+    offset = jedisCluster.bitpos(foo, true, new BitPosParams(1));
+    assertEquals(13, offset);
+    offset = jedisCluster.bitpos(foo, false, new BitPosParams(1));
+    assertEquals(8, offset);
+
+    offset = jedisCluster.bitpos(foo, true, new BitPosParams(2, 3));
+    assertEquals(-1, offset);
+    offset = jedisCluster.bitpos(foo, false, new BitPosParams(2, 3));
+    assertEquals(16, offset);
+
+    offset = jedisCluster.bitpos(foo, true, new BitPosParams(3, 4));
+    assertEquals(39, offset);
+  }
+
+  @Test
+  public void bitposBinary() {
+    // binary
+    byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
+    String foo = new String(bfoo);
+
+    jedisCluster.set(bfoo, Protocol.toByteArray(0));
+
+    jedisCluster.setbit(bfoo, 3, true);
+    jedisCluster.setbit(bfoo, 7, true);
+    jedisCluster.setbit(bfoo, 13, true);
+    jedisCluster.setbit(bfoo, 39, true);
+
+    /*
+     * byte: 0 1 2 3 4 bit: 00010001 / 00000100 / 00000000 / 00000000 / 00000001
+     */
+    long offset = jedisCluster.bitpos(foo, true);
+    assertEquals(2, offset);
+    offset = jedisCluster.bitpos(foo, false);
+    assertEquals(0, offset);
+
+    offset = jedisCluster.bitpos(foo, true, new BitPosParams(1));
+    assertEquals(13, offset);
+    offset = jedisCluster.bitpos(foo, false, new BitPosParams(1));
+    assertEquals(8, offset);
+
+    offset = jedisCluster.bitpos(foo, true, new BitPosParams(2, 3));
+    assertEquals(-1, offset);
+    offset = jedisCluster.bitpos(foo, false, new BitPosParams(2, 3));
+    assertEquals(16, offset);
+
+    offset = jedisCluster.bitpos(foo, true, new BitPosParams(3, 4));
+    assertEquals(39, offset);
+  }
+
+  @Test
+  public void bitposWithNoMatchingBitExist() {
+    String foo = "foo";
+
+    jedisCluster.set(foo, String.valueOf(0));
+    for (int idx = 0; idx < 8; idx++) {
+      jedisCluster.setbit(foo, idx, true);
+    }
+
+    /*
+     * byte: 0 bit: 11111111
+     */
+    long offset = jedisCluster.bitpos(foo, false);
+    // offset should be last index + 1
+    assertEquals(8, offset);
+  }
+
+  @Test
+  public void bitposWithNoMatchingBitExistWithinRange() {
+    String foo = "foo";
+
+    jedisCluster.set(foo, String.valueOf(0));
+    for (int idx = 0; idx < 8 * 5; idx++) {
+      jedisCluster.setbit(foo, idx, true);
+    }
+
+    /*
+     * byte: 0 1 2 3 4 bit: 11111111 / 11111111 / 11111111 / 11111111 / 11111111
+     */
+    long offset = jedisCluster.bitpos(foo, false, new BitPosParams(2, 3));
+    // offset should be -1
+    assertEquals(-1, offset);
+  }
+
+  @Test
+  public void setAndgetrange() {
+    jedisCluster.set("key1", "Hello World");
+    long reply = jedisCluster.setrange("key1", 6, "Jedis");
+    assertEquals(11, reply);
+
+    assertEquals("Hello Jedis", jedisCluster.get("key1"));
+
+    assertEquals("Hello", jedisCluster.getrange("key1", 0, 4));
+    assertEquals("Jedis", jedisCluster.getrange("key1", 6, 11));
+  }
+
+  @Test
+  public void bitCount() {
+    jedisCluster.setbit("foo", 16, true);
+    jedisCluster.setbit("foo", 24, true);
+    jedisCluster.setbit("foo", 40, true);
+    jedisCluster.setbit("foo", 56, true);
+
+    long c4 = jedisCluster.bitcount("foo");
+    assertEquals(4, c4);
+
+    long c3 = jedisCluster.bitcount("foo", 2L, 5L);
+    assertEquals(3, c3);
+  }
+
+  @Test
+  public void bitOp() {
+    jedisCluster.set(foo1, "\u0060");
+    jedisCluster.set(foo2, "\u0044");
+
+    jedisCluster.bitop(BitOP.AND, Key_resultAnd, foo1, foo2);
+    String resultAnd = jedisCluster.get(Key_resultAnd);
+    assertEquals("\u0040", resultAnd);
+
+    jedisCluster.bitop(BitOP.OR, Key_resultOr,  foo1, foo2);
+    String resultOr = jedisCluster.get(Key_resultOr);
+    assertEquals("\u0064", resultOr);
+
+    jedisCluster.bitop(BitOP.XOR, Key_resultXor, foo1, foo2);
+    String resultXor = jedisCluster.get(Key_resultXor);
+    assertEquals("\u0024", resultXor);
+  }
+
+  @Test
+  public void bitOpNot() {
+    jedisCluster.setbit(foo, 0, true);
+    jedisCluster.setbit(foo, 4, true);
+
+    jedisCluster.bitop(BitOP.NOT, Key_resultNot, foo);
+
+    String resultNot = jedisCluster.get(Key_resultNot);
+    assertEquals("\u0077", resultNot);
+  }
+
+  @Test(expected = redis.clients.jedis.exceptions.JedisDataException.class)
+  public void bitOpNotMultiSourceShouldFail() {
+    jedisCluster.bitop(BitOP.NOT, "dest", "src1", "src2");
+  }
+
+  @Test
+  public void testBitfield() {
+    List responses = jedisCluster.bitfield("mykey", "INCRBY","i5","100","1", "GET", "u4", "0");
+    assertEquals(1L, responses.get(0).longValue());
+    assertEquals(0L, responses.get(1).longValue());
+  }
+
+  @Test
+  public void testBinaryBitfield() {
+    List responses = jedisCluster.bitfield(SafeEncoder.encode("mykey"), SafeEncoder.encode("INCRBY"),
+            SafeEncoder.encode("i5"), SafeEncoder.encode("100"), SafeEncoder.encode("1"),
+            SafeEncoder.encode("GET"), SafeEncoder.encode("u4"), SafeEncoder.encode("0")
+    );
+    assertEquals(1L, responses.get(0).longValue());
+    assertEquals(0L, responses.get(1).longValue());
+  }
+
+}
diff --git a/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/GeoCommandsTest.java b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/GeoCommandsTest.java
new file mode 100644
index 0000000..651f264
--- /dev/null
+++ b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/GeoCommandsTest.java
@@ -0,0 +1,386 @@
+package io.opentracing.contrib.redis.jediscluster.commands;
+
+import org.junit.Test;
+import redis.clients.jedis.GeoCoordinate;
+import redis.clients.jedis.GeoRadiusResponse;
+import redis.clients.jedis.GeoUnit;
+import redis.clients.jedis.params.geo.GeoRadiusParam;
+import redis.clients.util.SafeEncoder;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class GeoCommandsTest extends JedisCommandTestBase {
+  final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
+  final byte[] bA = { 0x0A };
+  final byte[] bB = { 0x0B };
+  final byte[] bC = { 0x0C };
+  final byte[] bD = { 0x0D };
+  final byte[] bNotexist = { 0x0F };
+
+  @Test
+  public void geoadd() {
+    long size = jedisCluster.geoadd("foo", 1, 2, "a");
+    assertEquals(1, size);
+    size = jedisCluster.geoadd("foo", 2, 3, "a");
+    assertEquals(0, size);
+
+    Map coordinateMap = new HashMap();
+    coordinateMap.put("a", new GeoCoordinate(3, 4));
+    coordinateMap.put("b", new GeoCoordinate(2, 3));
+    coordinateMap.put("c", new GeoCoordinate(3.314, 2.3241));
+
+    size = jedisCluster.geoadd("foo", coordinateMap);
+    assertEquals(2, size);
+
+    // binary
+    size = jedisCluster.geoadd(bfoo, 1, 2, bA);
+    assertEquals(1, size);
+    size = jedisCluster.geoadd(bfoo, 2, 3, bA);
+    assertEquals(0, size);
+
+    Map bcoordinateMap = new HashMap();
+    bcoordinateMap.put(bA, new GeoCoordinate(3, 4));
+    bcoordinateMap.put(bB, new GeoCoordinate(2, 3));
+    bcoordinateMap.put(bC, new GeoCoordinate(3.314, 2.3241));
+
+    size = jedisCluster.geoadd(bfoo, bcoordinateMap);
+    assertEquals(2, size);
+  }
+
+  @Test
+  public void geodist() {
+    prepareGeoData();
+
+    Double dist = jedisCluster.geodist("foo", "a", "b");
+    assertEquals(157149, dist.intValue());
+
+    dist = jedisCluster.geodist("foo", "a", "b", GeoUnit.KM);
+    assertEquals(157, dist.intValue());
+
+    dist = jedisCluster.geodist("foo", "a", "b", GeoUnit.MI);
+    assertEquals(97, dist.intValue());
+
+    dist = jedisCluster.geodist("foo", "a", "b", GeoUnit.FT);
+    assertEquals(515583, dist.intValue());
+
+    // binary
+    dist = jedisCluster.geodist(bfoo, bA, bB);
+    assertEquals(157149, dist.intValue());
+
+    dist = jedisCluster.geodist(bfoo, bA, bB, GeoUnit.KM);
+    assertEquals(157, dist.intValue());
+
+    dist = jedisCluster.geodist(bfoo, bA, bB, GeoUnit.MI);
+    assertEquals(97, dist.intValue());
+
+    dist = jedisCluster.geodist(bfoo, bA, bB, GeoUnit.FT);
+    assertEquals(515583, dist.intValue());
+  }
+
+  @Test
+  public void geohash() {
+    prepareGeoData();
+
+    List hashes = jedisCluster.geohash("foo", "a", "b", "notexist");
+    assertEquals(3, hashes.size());
+    assertEquals("s0dnu20t9j0", hashes.get(0));
+    assertEquals("s093jd0k720", hashes.get(1));
+    assertNull(hashes.get(2));
+
+    // binary
+    List bhashes = jedisCluster.geohash(bfoo, bA, bB, bNotexist);
+    assertEquals(3, bhashes.size());
+    assertArrayEquals(SafeEncoder.encode("s0dnu20t9j0"), bhashes.get(0));
+    assertArrayEquals(SafeEncoder.encode("s093jd0k720"), bhashes.get(1));
+    assertNull(bhashes.get(2));
+  }
+
+  @Test
+  public void geopos() {
+    prepareGeoData();
+
+    List coordinates = jedisCluster.geopos("foo", "a", "b", "notexist");
+    assertEquals(3, coordinates.size());
+    assertTrue(equalsWithinEpsilon(3.0, coordinates.get(0).getLongitude()));
+    assertTrue(equalsWithinEpsilon(4.0, coordinates.get(0).getLatitude()));
+    assertTrue(equalsWithinEpsilon(2.0, coordinates.get(1).getLongitude()));
+    assertTrue(equalsWithinEpsilon(3.0, coordinates.get(1).getLatitude()));
+    assertNull(coordinates.get(2));
+
+    List bcoordinates = jedisCluster.geopos(bfoo, bA, bB, bNotexist);
+    assertEquals(3, bcoordinates.size());
+    assertTrue(equalsWithinEpsilon(3.0, bcoordinates.get(0).getLongitude()));
+    assertTrue(equalsWithinEpsilon(4.0, bcoordinates.get(0).getLatitude()));
+    assertTrue(equalsWithinEpsilon(2.0, bcoordinates.get(1).getLongitude()));
+    assertTrue(equalsWithinEpsilon(3.0, bcoordinates.get(1).getLatitude()));
+    assertNull(bcoordinates.get(2));
+  }
+
+  @Test
+  public void georadius() {
+    // prepare datas
+    Map coordinateMap = new HashMap();
+    coordinateMap.put("Palermo", new GeoCoordinate(13.361389, 38.115556));
+    coordinateMap.put("Catania", new GeoCoordinate(15.087269, 37.502669));
+    jedisCluster.geoadd("Sicily", coordinateMap);
+
+    List members = jedisCluster.georadius("Sicily", 15, 37, 200, GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    // sort
+    members = jedisCluster.georadius("Sicily", 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending());
+    assertEquals(2, members.size());
+    assertEquals("Catania", members.get(0).getMemberByString());
+    assertEquals("Palermo", members.get(1).getMemberByString());
+
+    // sort, count 1
+    members = jedisCluster.georadius("Sicily", 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1));
+    assertEquals(1, members.size());
+
+    // sort, count 1, withdist, withcoord
+    members = jedisCluster.georadius("Sicily", 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+    GeoRadiusResponse response = members.get(0);
+    assertTrue(equalsWithinEpsilon(56.4413, response.getDistance()));
+    assertTrue(equalsWithinEpsilon(15.087269, response.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.502669, response.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusReadonly() {
+    // prepare datas
+    Map coordinateMap = new HashMap();
+    coordinateMap.put("Palermo", new GeoCoordinate(13.361389, 38.115556));
+    coordinateMap.put("Catania", new GeoCoordinate(15.087269, 37.502669));
+    jedisCluster.geoadd("Sicily", coordinateMap);
+
+    List members = jedisCluster.georadiusReadonly("Sicily", 15, 37, 200, GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    // sort
+    members = jedisCluster.georadiusReadonly("Sicily", 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending());
+    assertEquals(2, members.size());
+    assertEquals("Catania", members.get(0).getMemberByString());
+    assertEquals("Palermo", members.get(1).getMemberByString());
+
+    // sort, count 1
+    members = jedisCluster.georadiusReadonly("Sicily", 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1));
+    assertEquals(1, members.size());
+
+    // sort, count 1, withdist, withcoord
+    members = jedisCluster.georadiusReadonly("Sicily", 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+    GeoRadiusResponse response = members.get(0);
+    assertTrue(equalsWithinEpsilon(56.4413, response.getDistance()));
+    assertTrue(equalsWithinEpsilon(15.087269, response.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.502669, response.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusBinary() {
+    // prepare datas
+    Map bcoordinateMap = new HashMap();
+    bcoordinateMap.put(bA, new GeoCoordinate(13.361389, 38.115556));
+    bcoordinateMap.put(bB, new GeoCoordinate(15.087269, 37.502669));
+    jedisCluster.geoadd(bfoo, bcoordinateMap);
+
+    List members = jedisCluster.georadius(bfoo, 15, 37, 200, GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    // sort
+    members = jedisCluster.georadius(bfoo, 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending());
+    assertEquals(2, members.size());
+    assertArrayEquals(bB, members.get(0).getMember());
+    assertArrayEquals(bA, members.get(1).getMember());
+
+    // sort, count 1
+    members = jedisCluster.georadius(bfoo, 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1));
+    assertEquals(1, members.size());
+
+    // sort, count 1, withdist, withcoord
+    members = jedisCluster.georadius(bfoo, 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+    GeoRadiusResponse response = members.get(0);
+    assertTrue(equalsWithinEpsilon(56.4413, response.getDistance()));
+    assertTrue(equalsWithinEpsilon(15.087269, response.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.502669, response.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusReadonlyBinary() {
+    // prepare datas
+    Map bcoordinateMap = new HashMap();
+    bcoordinateMap.put(bA, new GeoCoordinate(13.361389, 38.115556));
+    bcoordinateMap.put(bB, new GeoCoordinate(15.087269, 37.502669));
+    jedisCluster.geoadd(bfoo, bcoordinateMap);
+
+    List members = jedisCluster.georadiusReadonly(bfoo, 15, 37, 200, GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    // sort
+    members = jedisCluster.georadiusReadonly(bfoo, 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending());
+    assertEquals(2, members.size());
+    assertArrayEquals(bB, members.get(0).getMember());
+    assertArrayEquals(bA, members.get(1).getMember());
+
+    // sort, count 1
+    members = jedisCluster.georadiusReadonly(bfoo, 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1));
+    assertEquals(1, members.size());
+
+    // sort, count 1, withdist, withcoord
+    members = jedisCluster.georadiusReadonly(bfoo, 15, 37, 200, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+    GeoRadiusResponse response = members.get(0);
+    assertTrue(equalsWithinEpsilon(56.4413, response.getDistance()));
+    assertTrue(equalsWithinEpsilon(15.087269, response.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.502669, response.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusByMember() {
+    jedisCluster.geoadd("Sicily", 13.583333, 37.316667, "Agrigento");
+    jedisCluster.geoadd("Sicily", 13.361389, 38.115556, "Palermo");
+    jedisCluster.geoadd("Sicily", 15.087269, 37.502669, "Catania");
+
+    List members = jedisCluster.georadiusByMember("Sicily", "Agrigento", 100,
+      GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    members = jedisCluster.georadiusByMember("Sicily", "Agrigento", 100, GeoUnit.KM, GeoRadiusParam
+        .geoRadiusParam().sortAscending());
+    assertEquals(2, members.size());
+    assertEquals("Agrigento", members.get(0).getMemberByString());
+    assertEquals("Palermo", members.get(1).getMemberByString());
+
+    members = jedisCluster.georadiusByMember("Sicily", "Agrigento", 100, GeoUnit.KM, GeoRadiusParam
+        .geoRadiusParam().sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+
+    GeoRadiusResponse member = members.get(0);
+    assertEquals("Agrigento", member.getMemberByString());
+    assertTrue(equalsWithinEpsilon(0, member.getDistance()));
+    assertTrue(equalsWithinEpsilon(13.583333, member.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.316667, member.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusByMemberReadonly() {
+    jedisCluster.geoadd("Sicily", 13.583333, 37.316667, "Agrigento");
+    jedisCluster.geoadd("Sicily", 13.361389, 38.115556, "Palermo");
+    jedisCluster.geoadd("Sicily", 15.087269, 37.502669, "Catania");
+
+    List members = jedisCluster.georadiusByMemberReadonly("Sicily", "Agrigento", 100,
+      GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    members = jedisCluster.georadiusByMemberReadonly("Sicily", "Agrigento", 100, GeoUnit.KM, GeoRadiusParam
+        .geoRadiusParam().sortAscending());
+    assertEquals(2, members.size());
+    assertEquals("Agrigento", members.get(0).getMemberByString());
+    assertEquals("Palermo", members.get(1).getMemberByString());
+
+    members = jedisCluster.georadiusByMemberReadonly("Sicily", "Agrigento", 100, GeoUnit.KM, GeoRadiusParam
+        .geoRadiusParam().sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+
+    GeoRadiusResponse member = members.get(0);
+    assertEquals("Agrigento", member.getMemberByString());
+    assertTrue(equalsWithinEpsilon(0, member.getDistance()));
+    assertTrue(equalsWithinEpsilon(13.583333, member.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.316667, member.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusByMemberBinary() {
+    jedisCluster.geoadd(bfoo, 13.583333, 37.316667, bA);
+    jedisCluster.geoadd(bfoo, 13.361389, 38.115556, bB);
+    jedisCluster.geoadd(bfoo, 15.087269, 37.502669, bC);
+
+    List members = jedisCluster.georadiusByMember(bfoo, bA, 100, GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    members = jedisCluster.georadiusByMember(bfoo, bA, 100, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending());
+    assertEquals(2, members.size());
+    assertArrayEquals(bA, members.get(0).getMember());
+    assertArrayEquals(bB, members.get(1).getMember());
+
+    members = jedisCluster.georadiusByMember(bfoo, bA, 100, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+
+    GeoRadiusResponse member = members.get(0);
+    assertArrayEquals(bA, member.getMember());
+    assertTrue(equalsWithinEpsilon(0, member.getDistance()));
+    assertTrue(equalsWithinEpsilon(13.583333, member.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.316667, member.getCoordinate().getLatitude()));
+  }
+
+  @Test
+  public void georadiusByMemberReadonlyBinary() {
+    jedisCluster.geoadd(bfoo, 13.583333, 37.316667, bA);
+    jedisCluster.geoadd(bfoo, 13.361389, 38.115556, bB);
+    jedisCluster.geoadd(bfoo, 15.087269, 37.502669, bC);
+
+    List members = jedisCluster.georadiusByMemberReadonly(bfoo, bA, 100, GeoUnit.KM);
+    assertEquals(2, members.size());
+
+    members = jedisCluster.georadiusByMemberReadonly(bfoo, bA, 100, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending());
+    assertEquals(2, members.size());
+    assertArrayEquals(bA, members.get(0).getMember());
+    assertArrayEquals(bB, members.get(1).getMember());
+
+    members = jedisCluster.georadiusByMemberReadonly(bfoo, bA, 100, GeoUnit.KM, GeoRadiusParam.geoRadiusParam()
+        .sortAscending().count(1).withCoord().withDist());
+    assertEquals(1, members.size());
+
+    GeoRadiusResponse member = members.get(0);
+    assertArrayEquals(bA, member.getMember());
+    assertTrue(equalsWithinEpsilon(0, member.getDistance()));
+    assertTrue(equalsWithinEpsilon(13.583333, member.getCoordinate().getLongitude()));
+    assertTrue(equalsWithinEpsilon(37.316667, member.getCoordinate().getLatitude()));
+  }
+
+  private void prepareGeoData() {
+    Map coordinateMap = new HashMap();
+    coordinateMap.put("a", new GeoCoordinate(3, 4));
+    coordinateMap.put("b", new GeoCoordinate(2, 3));
+    coordinateMap.put("c", new GeoCoordinate(3.314, 2.3241));
+
+    long size = jedisCluster.geoadd("foo", coordinateMap);
+    assertEquals(3, size);
+
+    Map bcoordinateMap = new HashMap();
+    bcoordinateMap.put(bA, new GeoCoordinate(3, 4));
+    bcoordinateMap.put(bB, new GeoCoordinate(2, 3));
+    bcoordinateMap.put(bC, new GeoCoordinate(3.314, 2.3241));
+
+    size = jedisCluster.geoadd(bfoo, bcoordinateMap);
+    assertEquals(3, size);
+  }
+
+  private boolean equalsWithinEpsilon(double d1, double d2) {
+    double epsilon = 1E-5;
+    return Math.abs(d1 - d2) < epsilon;
+  }
+}
diff --git a/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/HashesCommandsTest.java b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/HashesCommandsTest.java
new file mode 100644
index 0000000..48afe4b
--- /dev/null
+++ b/opentracing-redis-jedis/src/test/java/io/opentracing/contrib/redis/jediscluster/commands/HashesCommandsTest.java
@@ -0,0 +1,464 @@
+package io.opentracing.contrib.redis.jediscluster.commands;
+
+import org.junit.Test;
+import redis.clients.jedis.ScanParams;
+import redis.clients.jedis.ScanResult;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static io.opentracing.contrib.redis.utils.AssertUtil.assertByteArrayListEquals;
+import static io.opentracing.contrib.redis.utils.AssertUtil.assertByteArraySetEquals;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static redis.clients.jedis.ScanParams.SCAN_POINTER_START;
+import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY;
+
+
+public class HashesCommandsTest extends JedisCommandTestBase {
+  final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
+  final byte[] bbar = { 0x05, 0x06, 0x07, 0x08 };
+  final byte[] bcar = { 0x09, 0x0A, 0x0B, 0x0C };
+
+  final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A };
+  final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B };
+  final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C };
+  final byte[] bbarstar = { 0x05, 0x06, 0x07, 0x08, '*' };
+
+  @Test
+  public void hset() {
+    long status = jedisCluster.hset("foo", "bar", "car");
+    assertEquals(1, status);
+    status = jedisCluster.hset("foo", "bar", "foo");
+    assertEquals(0, status);
+
+    // Binary
+    long bstatus = jedisCluster.hset(bfoo, bbar, bcar);
+    assertEquals(1, bstatus);
+    bstatus = jedisCluster.hset(bfoo, bbar, bfoo);
+    assertEquals(0, bstatus);
+
+  }
+
+  @Test
+  public void hget() {
+    jedisCluster.hset("foo", "bar", "car");
+    assertNull(jedisCluster.hget("bar", "foo"));
+    assertNull(jedisCluster.hget("foo", "car"));
+    assertEquals("car", jedisCluster.hget("foo", "bar"));
+
+    // Binary
+    jedisCluster.hset(bfoo, bbar, bcar);
+    assertNull(jedisCluster.hget(bbar, bfoo));
+    assertNull(jedisCluster.hget(bfoo, bcar));
+    assertArrayEquals(bcar, jedisCluster.hget(bfoo, bbar));
+  }
+
+  @Test
+  public void hsetnx() {
+    long status = jedisCluster.hsetnx("foo", "bar", "car");
+    assertEquals(1, status);
+    assertEquals("car", jedisCluster.hget("foo", "bar"));
+
+    status = jedisCluster.hsetnx("foo", "bar", "foo");
+    assertEquals(0, status);
+    assertEquals("car", jedisCluster.hget("foo", "bar"));
+
+    status = jedisCluster.hsetnx("foo", "car", "bar");
+    assertEquals(1, status);
+    assertEquals("bar", jedisCluster.hget("foo", "car"));
+
+    // Binary
+    long bstatus = jedisCluster.hsetnx(bfoo, bbar, bcar);
+    assertEquals(1, bstatus);
+    assertArrayEquals(bcar, jedisCluster.hget(bfoo, bbar));
+
+    bstatus = jedisCluster.hsetnx(bfoo, bbar, bfoo);
+    assertEquals(0, bstatus);
+    assertArrayEquals(bcar, jedisCluster.hget(bfoo, bbar));
+
+    bstatus = jedisCluster.hsetnx(bfoo, bcar, bbar);
+    assertEquals(1, bstatus);
+    assertArrayEquals(bbar, jedisCluster.hget(bfoo, bcar));
+
+  }
+
+  @Test
+  public void hmset() {
+    Map hash = new HashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    String status = jedisCluster.hmset("foo", hash);
+    assertEquals("OK", status);
+    assertEquals("car", jedisCluster.hget("foo", "bar"));
+    assertEquals("bar", jedisCluster.hget("foo", "car"));
+
+    // Binary
+    Map bhash = new HashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    String bstatus = jedisCluster.hmset(bfoo, bhash);
+    assertEquals("OK", bstatus);
+    assertArrayEquals(bcar, jedisCluster.hget(bfoo, bbar));
+    assertArrayEquals(bbar, jedisCluster.hget(bfoo, bcar));
+
+  }
+
+  @Test
+  public void hsetVariadic() {
+    Map hash = new HashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    long status = jedisCluster.hset("foo", hash);
+    assertEquals(2, status);
+    assertEquals("car", jedisCluster.hget("foo", "bar"));
+    assertEquals("bar", jedisCluster.hget("foo", "car"));
+
+    // Binary
+    Map bhash = new HashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    status = jedisCluster.hset(bfoo, bhash);
+    assertEquals(2, status);
+    assertArrayEquals(bcar, jedisCluster.hget(bfoo, bbar));
+    assertArrayEquals(bbar, jedisCluster.hget(bfoo, bcar));
+  }
+
+  @Test
+  public void hmget() {
+    Map hash = new HashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    jedisCluster.hmset("foo", hash);
+
+    List values = jedisCluster.hmget("foo", "bar", "car", "foo");
+    List expected = new ArrayList();
+    expected.add("car");
+    expected.add("bar");
+    expected.add(null);
+
+    assertEquals(expected, values);
+
+    // Binary
+    Map bhash = new HashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bhash);
+
+    List bvalues = jedisCluster.hmget(bfoo, bbar, bcar, bfoo);
+    List bexpected = new ArrayList();
+    bexpected.add(bcar);
+    bexpected.add(bbar);
+    bexpected.add(null);
+
+    assertByteArrayListEquals(bexpected, bvalues);
+  }
+
+  @Test
+  public void hincrBy() {
+    long value = jedisCluster.hincrBy("foo", "bar", 1);
+    assertEquals(1, value);
+    value = jedisCluster.hincrBy("foo", "bar", -1);
+    assertEquals(0, value);
+    value = jedisCluster.hincrBy("foo", "bar", -10);
+    assertEquals(-10, value);
+
+    // Binary
+    long bvalue = jedisCluster.hincrBy(bfoo, bbar, 1);
+    assertEquals(1, bvalue);
+    bvalue = jedisCluster.hincrBy(bfoo, bbar, -1);
+    assertEquals(0, bvalue);
+    bvalue = jedisCluster.hincrBy(bfoo, bbar, -10);
+    assertEquals(-10, bvalue);
+
+  }
+
+  @Test
+  public void hincrByFloat() {
+    Double value = jedisCluster.hincrByFloat("foo", "bar", 1.5d);
+    assertEquals((Double) 1.5d, value);
+    value = jedisCluster.hincrByFloat("foo", "bar", -1.5d);
+    assertEquals((Double) 0d, value);
+    value = jedisCluster.hincrByFloat("foo", "bar", -10.7d);
+    assertEquals(Double.valueOf(-10.7d), value);
+
+    // Binary
+    double bvalue = jedisCluster.hincrByFloat(bfoo, bbar, 1.5d);
+    assertEquals(1.5d, bvalue, 0d);
+    bvalue = jedisCluster.hincrByFloat(bfoo, bbar, -1.5d);
+    assertEquals(0d, bvalue, 0d);
+    bvalue = jedisCluster.hincrByFloat(bfoo, bbar, -10.7d);
+    assertEquals(-10.7d, bvalue, 0d);
+
+  }
+
+  @Test
+  public void hexists() {
+    Map hash = new HashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    jedisCluster.hmset("foo", hash);
+
+    assertFalse(jedisCluster.hexists("bar", "foo"));
+    assertFalse(jedisCluster.hexists("foo", "foo"));
+    assertTrue(jedisCluster.hexists("foo", "bar"));
+
+    // Binary
+    Map bhash = new HashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bhash);
+
+    assertFalse(jedisCluster.hexists(bbar, bfoo));
+    assertFalse(jedisCluster.hexists(bfoo, bfoo));
+    assertTrue(jedisCluster.hexists(bfoo, bbar));
+
+  }
+
+  @Test
+  public void hdel() {
+    Map hash = new HashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    jedisCluster.hmset("foo", hash);
+
+    assertEquals(0, jedisCluster.hdel("bar", "foo").intValue());
+    assertEquals(0, jedisCluster.hdel("foo", "foo").intValue());
+    assertEquals(1, jedisCluster.hdel("foo", "bar").intValue());
+    assertNull(jedisCluster.hget("foo", "bar"));
+
+    // Binary
+    Map bhash = new HashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bhash);
+
+    assertEquals(0, jedisCluster.hdel(bbar, bfoo).intValue());
+    assertEquals(0, jedisCluster.hdel(bfoo, bfoo).intValue());
+    assertEquals(1, jedisCluster.hdel(bfoo, bbar).intValue());
+    assertNull(jedisCluster.hget(bfoo, bbar));
+
+  }
+
+  @Test
+  public void hlen() {
+    Map hash = new HashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    jedisCluster.hmset("foo", hash);
+
+    assertEquals(0, jedisCluster.hlen("bar").intValue());
+    assertEquals(2, jedisCluster.hlen("foo").intValue());
+
+    // Binary
+    Map bhash = new HashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bhash);
+
+    assertEquals(0, jedisCluster.hlen(bbar).intValue());
+    assertEquals(2, jedisCluster.hlen(bfoo).intValue());
+
+  }
+
+  @Test
+  public void hkeys() {
+    Map hash = new LinkedHashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    jedisCluster.hmset("foo", hash);
+
+    Set keys = jedisCluster.hkeys("foo");
+    Set expected = new LinkedHashSet();
+    expected.add("bar");
+    expected.add("car");
+    assertEquals(expected, keys);
+
+    // Binary
+    Map bhash = new LinkedHashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bhash);
+
+    Set bkeys = jedisCluster.hkeys(bfoo);
+    Set bexpected = new LinkedHashSet();
+    bexpected.add(bbar);
+    bexpected.add(bcar);
+    assertByteArraySetEquals(bexpected, bkeys);
+  }
+
+  @Test
+  public void hvals() {
+    Map hash = new LinkedHashMap();
+    hash.put("bar", "car");
+    hash.put("car", "bar");
+    jedisCluster.hmset("foo", hash);
+
+    List vals = jedisCluster.hvals("foo");
+    assertEquals(2, vals.size());
+    assertTrue(vals.contains("bar"));
+    assertTrue(vals.contains("car"));
+
+    // Binary
+    Map bhash = new LinkedHashMap();
+    bhash.put(bbar, bcar);
+    bhash.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bhash);
+
+    List bvals = new ArrayList<>(jedisCluster.hvals(bfoo));
+
+    assertEquals(2, bvals.size());
+    assertTrue(arrayContains(bvals, bbar));
+    assertTrue(arrayContains(bvals, bcar));
+  }
+
+  @Test
+  public void hgetAll() {
+    Map h = new HashMap();
+    h.put("bar", "car");
+    h.put("car", "bar");
+    jedisCluster.hmset("foo", h);
+
+    Map hash = jedisCluster.hgetAll("foo");
+    assertEquals(2, hash.size());
+    assertEquals("car", hash.get("bar"));
+    assertEquals("bar", hash.get("car"));
+
+    // Binary
+    Map bh = new HashMap();
+    bh.put(bbar, bcar);
+    bh.put(bcar, bbar);
+    jedisCluster.hmset(bfoo, bh);
+    Map