6

I've two java applications (app1, app2). Both applications are using JedisCluster client for Redis cluster. app1 write or read data from Redis cluster. app2 is like a scheduler which only writes some data to Redis cluster. it runs after a fixed time of interval. I've to ensure that when app2 is doing write operation, no data is served or written for app1 until the whole write operation is finished by app2. I want to lock Redis cluster for app1 when app2 is running. it doesn't matter whether app1 get an exception or not at that time.

Kaidul
  • 15,409
  • 15
  • 81
  • 150
Md Shihab Uddin
  • 541
  • 5
  • 13

3 Answers3

5

It seems you need application-level lock to ensure thread-safe operations from different application scopes which is pretty much same as distributed lock. For Jedis, a quick search yields Jedis-lock library.

Jedis jedis = new Jedis("localhost");
JedisLock lock = new JedisLock(jedis, "lockname", 10000, 30000);
lock.acquire();
try {
  // do some stuff
}
finally {
  lock.release();
}

System.out.println(jedis.isLocked());
System.out.println(jedis.isRemoteLocked());

Edit

According to Jedis-lock's owner (Thanks for this project), the project is no longer maintained/pull requests are not merged anymore. This fork is now actively maintained and has new features:

  • New SET API in place of old SETNX
  • Lock ownership safety using atomic LUA scripting on release()
  • Locking support for JedisCluster
Kaidul
  • 15,409
  • 15
  • 81
  • 150
  • What if the application crashes before executing finally block, it may leave the Redis locked forever, better to aquire lock using some time out. – AmanSinghal Apr 25 '17 at 05:27
  • 1
    @AmanSinghal yes, you're right but the API used here `JedisLock(Jedis jedis, String lockKey, int acquireTimeoutMillis, int expiryTimeMillis)` which I set 30000 here. So it will timeout eventually if any malfunctions occur. – Kaidul Apr 25 '17 at 05:40
  • Yup, I noticed that just want to highlight it so as to make people aware of this problem. – AmanSinghal Apr 25 '17 at 07:16
5

Have you tried Redisson's lock? It's a Redis based framework.

It offers Lock object implemented java.util.concurrent.locks.Lock interface and easy to use.

RedissonClient redisson = Redisson.create(config);

RLock lock = redisson.getLock("myLock");
lock.lock();
try {
   // ...
} finally {
   lock.unlock();
}

It also offers Asynchronous version of lock object.

Nikita Koksharov
  • 10,283
  • 1
  • 62
  • 71
0

I've achieved mutual exclusion on a race condition on Jedis, using Distributed locks with Redis because "GETs" are no threadsafe there is a need to implement mutex on a multithreaded environment. this was implemented with a JedisSentinelPool on getJedis()

 public void methodWithRaceCondition() {

    Jedis jedis = getJedis();
    try {
         lock();

        //code that requires multiple exclusion on data read
        jedis.//get hget ....


    } catch (Exception up) {
        logException(up);

    } finally {
        //ALWAYS RELEASE LOCK
        releaseLock(jedis);
        closeJedis(jedis);
        jedis = null;
    }
 }

 private void releaseLock(Jedis jedis) {
    String semaphore = "SEMAPHORE";
    try {
        if (!jedis.get(semaphore).isEmpty()) {
            jedis.del(semaphore);
        }
    } catch (final RuntimeException e) {
        LOGGER_SUB.error(e);
    }
}

private void lock(Jedis jedis) throws InterruptedException {
    synchronized (this) {
        try {
            String lock = openSemaphore(jedis);
            while (lock == null || "OK".compareTo(lock) != 0) {
                this.wait(1);
                LOGGER_SUB.info("WAITED");
                lock = openSemaphore(jedis);
            }
        } catch (final RuntimeException e) {
            LOGGER_SUB.error(e);
        }
    }
}

/**
 * Distributed locks with Redis
 * https://redis.io/topics/distlock
 * Set value =1
 * NX if not exixts
 * PX for millisec
 *
 * @param jedis
 * @return
 */
private String openSemaphore(Jedis jedis) {
    return jedis.set("SEMAPHORE", "1", "NX", "PX", 30000);
}
Andre Brito
  • 146
  • 8