Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get exclusive access to some session entry?

Due to remote invocation nature of REST services, they are in constant situation to run into race condition with each other. One of the everyday resources to race for is session. In order to be practical, you need to be able to put a lock over the resource at the beginning of your process and lift it up whenever you are done with it.

Now my question is, does Spring Session have any feature to deal with race condition over the session entries?

Or any other library / framework in Java!!!

like image 240
Mehran Avatar asked Mar 26 '16 12:03

Mehran


1 Answers

If you're using Spring Controllers, then you can use

RequestMappingHandlerAdapter.setSynchronizeOnSession-boolean-

This will make every Controller method synchronized in presence of a session.

HttpSession.setAttribute is thread safe. However getAttribute followed by setAttribute has to be manually made tread safe.

synchronized(session) {
    session.setAttribute("foo", "bar");
    session.getAttribute("foo");
}

Same can be done in case of spring session beans.

synchronized(session) {
    //do something with the session bean
}

#Edit

In case of multiple containers with normal spring session beans you would have to use sticky sessions. That would ensure that one session state is stored on one container and that container is accessed every single time the same session is requested. This has to be done on the load balancer with the help of something like BigIP cookies. Rest would would work the same way as for a single session there exists a single container, so locking session would suffice.

If you would like to use session sharing across instances there are supports on the containers like Tomcat and Jetty

These approaches use a back-end database or some other persistence mechanism to store state.

For the same purpose you can try using Spring Session. Which is trivial to configure with the Redis. Since Redis is single threaded, it ensures that one instance of an entry is accessed atomically.

Above approaches are non invasive. Both the database and Redis based approaches support transactions.

However if you want more control over the distributed state and locking you can try using the distributed data grids like Hazelcast and Gemfire.

I have personally worked with the Hazelcast and it does provide methods to lock entries made in the map.

#Edit2

Though I believe that handling transactions should suffice with Spring Session and Redis, to make sure you would need distributed locking. Lock object would have to be acquired from the Redis itself. Since Redis is single threaded a personal implementation would also work by using something like INCR

Algorithm would go something like below

//lock_num is the semaphore/lock object

lock_count = INCR lock_num
while(true) {
    if(lock_count != 1) {
        DECR lock_num
    } else {
        break
    }
    wait(wait_time_period)
}

//do processing in critical section

DECR lock_num

However, thankfully Spring already provides this distributed lock implementation via RedisLockRegistry. More documentation on usage is here.

If you decide to use plain Jedis without spring then here is a distributed lock as for Jedis : Jedis Lock.

//from https://github.com/abelaska/jedis-lock
Jedis jedis = new Jedis("localhost");
JedisLock lock = new JedisLock(jedis, "lockname", 10000, 30000);
lock.acquire();
try {
  // do some stuff
}
finally {
  lock.release();
}

Both of these should work exactly like Hazelcast locking.

like image 129
11thdimension Avatar answered Oct 20 '22 07:10

11thdimension