skip to Main Content

I am looking at a problem, where I have an object that contains a string key, and a counter. Every time the object is accessed the counter is decremented. This brings in the problem of race conditions. To handle this I have coded the following, using the synchronized keyword

try {
            option = cartRepository.findById(url);
            Rate rate = option.get();
            synchronized (this) {
                if(rate.getRate() > 0) {
                    rate.decRate(1);
                    allow = true;
                    cartRepository.save(rate);
                } 
            }
        } catch(NoSuchElementException e) {
            cartRepository.save(new Rate(url, 5));
            allow = true;
        } 

I was wondering, if redis itself has functionality that increments or in this case decrements a counter every time you access on that key.
The docs are a tad confusing. it does talk about auto increment on a key. But I am guessing, its not creating a two part key, with the key and counter. But autoincrements a key every time you create and save a new object.

2

Answers


  1. Chosen as BEST ANSWER

    With thanks to Sergie, this is the working code

    public boolean isAllowed(String url, String maxRate) {
            logger.info("URL is "+url);
            boolean allow = false;
            ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
            String rate = valueOps.get(url);
            logger.info("RATE "+rate);
            if(rate == null) {
                valueOps.set(url, maxRate, 5, TimeUnit.SECONDS);
                allow = true;
            } else {
                valueOps.decrement(url, 1);
                if(Integer.parseInt(rate) > 0) {
                    allow = true;
                }
            }
            return allow;
        }
    

  2. You can have a key to hold the counter and use INCR command to change counter value. This command returns the counter value after operation is performed.

    You can use ValueOperations in Spring Data Redis to issue this command. Here’s sample code:

    StringRedisTemplate rt = new StringRedisTemplate(factory);
    
    ValueOperations<String, String> valueOps = rt.opsForValue();
    
    valueOps.set(KEY, "10");
    System.out.println(valueOps.get(key));
    System.out.println(valueOps.increment(KEY, 1));
    System.out.println(valueOps.increment(KEY, 1));
    System.out.println(valueOps.increment(KEY, -1));
    

    The output will be:

    10
    11
    12
    11
    

    In case you have many counters to maintain you can store them in a hashmap and use HINCRBY command. With Spring Data Redis you can use HashOperations to manipulate values in the hash. See this page for more detailed explanation.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search