Search code examples
springjedisspring-data-redis

How to detect watch/exec failure when using Jedis?


This is the sequence of operations I am trying to do:

WATCH somekey
MULTI
...
SET somekey somevalue
EXEC

I do this via the execute(SessionCallback) method of RedisTemplate (pseudocode):

l = template.execute({
  ops.watch("somekey");
  ops.multi()
  ops.opsForValue().set("somekey", "somevalue")
  return ops.exec()
})

My problem is that when using jedis, l is not null but an empty list, and thus exec failures are indistinguishable from exec successes as there are no operations inside multi that return results.

This seems to be confirmed by the unit tests here: https://github.com/spring-projects/spring-data-redis/blob/1.8.4.RELEASE/src/test/java/org/springframework/data/redis/core/RedisTemplateTests.java#L740 where to test failure this is done:

if (redisTemplate.getConnectionFactory() instanceof JedisConnectionFactory) {
    assertThat(results, is(empty()));
} else {
    assertNull(results);
}

Compare to the testUnwatch test just below it that tests successful exec after unwatch and also expects an empty list (results.isEmpty()).

How do I distinguish between these two cases when using Jedis?


Solution

  • TL;DR

    You can't detect a transaction rollback using Jedis.

    Explanation

    Jedis returns, in any case, a List object in the currently available versions (2.8.2, 2.9.0). This change was part of code cleanup to prevent Jedis from returning null on exec(…) if the Redis transaction was rolled back.

    Right now, Jedis rolled back the change but there was no Jedis release for about a year now.

    If detecting transaction rollbacks are essential to your requirements, try a different Redis client.