Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-safe increment/decrement with StackExchange.Redis

I'm using the StackExchange.Redis package as a shared store for a multi-threaded application that will in turn be running on multiple servers simultaneously...so multi-multi-threaded ;)

One of the simplest use cases I have is that I want to keep a basic count on a series of keys (i.e. KEY1=4 KEY2=7, KEY3=13, etc). And I'll have business rules in place to enforce the max permissible value allowed for a given key. So for example, say KEY1 can only ever go as high as 5...if two threads fire at exactly the same time trying to increment it, I only want to allow one of them to succeed.

I believe I can accomplish this with a transaction by first fetching the current value and then making it condition that the value hasn't changed. Will this work as I am expecting? Is there a more elegant way to do this?

    public void Increment(string key) {        
        IDatabase db = redisConn.GetDatabase();
        var val = db.StringGet(key);
        int maxVal = 5; 
        if (Convert.ToInt32(val) < maxVal) {
            var trans = db.CreateTransaction();
            trans.AddCondition(Condition.StringEqual(key, val));
            trans.StringIncrementAsync(key);
            trans.Execute();
        }
    }

PS: Love this package, it's a pleasure to work with

like image 603
bruiseruser Avatar asked May 04 '15 20:05

bruiseruser


1 Answers

Yes, that should work fine. But it may be both easier and more efficient to use a Lua script via ScriptEvaluate.

Note: with your current code, you may want to check the response of Execute and "redo from start" if false. If a thread-race happens when moving from 2 to 3, with your current code: the update would be discarded. This wouldn't be an issue with a Lua script.

like image 77
Marc Gravell Avatar answered Sep 20 '22 04:09

Marc Gravell