skip to Main Content

I have some problem to use Redis pipeline. I need to execute 2 commands (incr() and set()) by a Redis transaction.

Environment info: redis-py version 3.5.3; the version of the Redis server is v=5.0.5.

So I have tried to use the following code (the code example is reproducible):

import redis

r = redis.Redis()
pipe = r.pipeline()

def redis_insertion():
    pipe.multi()
    testIndex = pipe.incr('testIndex')
    pipe.set('new_key:' + str(testIndex), 'new_value')
    pipe.execute()
    pipe.reset()

redis_insertion()

By Monitor I can see the real commands executed by the redis server:

> redis-cli monitor
OK
1684750490.821375 [0 127.0.0.1:47322] "MULTI"
1684750490.821394 [0 127.0.0.1:47322] "INCRBY" "testIndex" "1"
1684750490.821400 [0 127.0.0.1:47322] "SET" "new_key:Pipeline<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>" "new_value"
1684750490.821411 [0 127.0.0.1:47322] "EXEC"

The problem is that the instruction pipe.set('new_key:' + str(testIndex), 'new_value') return:

Pipeline<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>

instead of the value of the key testIndex after the execution of the INCRBY instruction.

Could someone explain me this behaviour?

2

Answers


  1. Chosen as BEST ANSWER

    By the answer of @Simon Prickett and especially thanks to his comment:

    If you need to work on the value then either get it first and watch the "somekey" key while you do your "set command", or use a Lua script that executes atomically on the redis server to perform this logic.

    I have changed my code as below:

    import redis
    
    r = redis.Redis()
    pipe = r.pipeline()
    
    def redis_insertion():
        pipe.watch('testIndex')
        testIndex = int(r.get('testIndex'))
        pipe.multi()
        testIndex += 1
        pipe.set('testIndex', testIndex)
        pipe.set('new_key:' + str(testIndex), 'new_value')
        pipe.execute()
        pipe.reset()
    
    redis_insertion()
    

    In this case the monitor shows:

    > redis-cli monitor
    OK
    1684824514.507417 [0 127.0.0.1:46494] "WATCH" "testIndex"
    1684824514.507815 [0 127.0.0.1:46496] "GET" "testIndex"
    1684824514.508060 [0 127.0.0.1:46494] "MULTI"
    1684824514.508073 [0 127.0.0.1:46494] "SET" "testIndex" "37"
    1684824514.508080 [0 127.0.0.1:46494] "SET" "new_key:37" "new_value"
    1684824514.508087 [0 127.0.0.1:46494] "EXEC"
    1684824514.508670 [0 127.0.0.1:46494] "GET" "testIndex"
    

    The output of the monitor shows that in the Redis DB have been correctly inserted the keys:

    • testIndex=37 ("SET" "testIndex" "37")
    • new_key:37='new_value' ("SET" "new_key:37" "new_value")

  2. The execute function returns a list of command responses from Redis, so your incr response should be the first thing in that list.

    Example:

    from redis import Redis
    
    redis_client = Redis(decode_responses=True)
    
    pipeline = redis_client.pipeline(transaction=False)
    
    pipeline.incr("somekey", 1)
    pipeline.set("hello", "world")
    pipeline.get("hello")
    responses = pipeline.execute()
    
    print(responses)
    

    Output:

    $ python demo.py
    [3, True, 'world']
    

    Versions:

    $ cat requirements.txt
    async-timeout==4.0.2
    redis==4.5.5
    $ python --version
    Python 3.10.7
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search