RedisJSON / redisjson-py

An extension to redis-py for using Redis' ReJSON module
https://redisjson.io
BSD 2-Clause "Simplified" License
160 stars 34 forks source link

Exception when using Redis-Pool #59

Closed clmnin closed 2 years ago

clmnin commented 2 years ago

I get decoding exception when I use a redis-pool along with rejson client.

I'll use the same code as the Usage Example in README

from rejson import Client, Path
import redis

redis_pool = None

def redis_create_pool() -> None:
    """
    Get redis pool and init it globally.
    This is done at the start of main.py
    """
    # Redis client bound to pool of connections (auto-reconnecting).
    global redis_pool
    redis_pool = redis.ConnectionPool.from_url("redis://localhost", max_connections=10)

redis_create_pool()
rj = Client(decode_responses=True, connection_pool=redis_pool)

# Set the key `obj` to some object
obj = {
    'answer': 42,
    'arr': [None, True, 3.14],
    'truth': {
        'coord': 'out there'
    }
}
rj.jsonset('obj', Path.rootPath(), obj)

# Get something
print('Is there anybody... {}?'.format(rj.jsonget('obj', Path('.truth.coord'))))

# Delete something (or perhaps nothing), append something and pop it
rj.jsondel('obj', Path('.arr[0]'))
rj.jsonarrappend('obj', Path('.arr'), 'something')
print('{} popped!'.format(rj.jsonarrpop('obj', Path('.arr'))))

# Update something else
rj.jsonset('obj', Path('.answer'), 2.17)

# And use just like the regular redis-py client
jp = rj.pipeline()
jp.set('foo', 'bar')
jp.jsonset('baz', Path.rootPath(), 'qaz')
jp.execute()

# If you use non-ascii character in your JSON data, you can add the no_escape flag to JSON.GET command
obj_non_ascii = {
    'non_ascii_string': 'hyvää'
}
rj.jsonset('non-ascii', Path.rootPath(), obj_non_ascii)
print('{} is a non-ascii string'.format(rj.jsonget('non-ascii', Path('.non_ascii_string'), no_escape=True)))

This is the diff

1a2
> import redis
3c4,17
< rj = Client(host='localhost', port=6379, decode_responses=True)
---
> redis_pool = None
> 
> def redis_create_pool() -> None:
>     """
>     Get redis pool and init it globally.
>     This is done at the start of main.py
>     """
>     # Redis client bound to pool of connections (auto-reconnecting).
>     global redis_pool
>     redis_pool = redis.ConnectionPool.from_url("redis://localhost", max_connections=10)
> 
> 
> redis_create_pool()
> rj = Client(decode_responses=True, connection_pool=redis_pool)

Exception

TypeError: cannot use a string pattern on a bytes-like object

bentsku commented 2 years ago

Hello,

You didn't set decode_responses to True when you initialized your ConnectionPool. The decode_responses is passed to the ConnectionPool object of the client when you create it.

Redis ConnectionPool are used by default when you initialize a Redis Client. Do you have a specific reason to initialize the ConnectionPool beforehand ?

You can skip the ConnectionPool part, and set up your rejson Client with the max_connection set to 10 and it would automatically create a connection pool managed by the Rejson client, that you can access atrj.connection_pool.

Here you can see the Redis client creating the ConnectionPool if you don't provide it at creation.

https://github.com/andymccurdy/redis-py/blob/9ed5cd7808789f791fdc7ee368bd268307ac9847/redis/client.py#L874-L875

Hope this helps

clmnin commented 2 years ago

@bentsku I'm using both rejson and redisearch. So my reasoning behind initializing a pool prehand is so that I can use the same pool for both the clients

import redis
import redisearch
import rejson

redis_pool = None

def redis_pool_get_con():
    return redis.Redis(connection_pool=redis_pool)

def redis_create_pool() -> None:
    global redis_pool
    redis_pool = redis.ConnectionPool.from_url("redis://localhost", max_connections=10)

redis_create_pool()
rs = redisearch.Client(index_name, conn=redis_pool_get_con())
rj = rejson.Client(decode_responses=True, connection_pool=redis_pool)

Is there a better way to use RediSearch and ReJSON?

bentsku commented 2 years ago

I don't know if there's a better way for your case, but I've checked in the RediSearch python client, and they use decode_responses as True for their ConnectionPool. So both ReJSON and RediSearch needs their ConnectionPool to have decode_responses set to True.

https://github.com/RediSearch/redisearch-py/blob/77ec182bff7039798037a8f1d069930e943fb745/redisearch/client.py#L245-L256

So for your case, when you create your ConnectionPool, set decode_responses to True.

def redis_create_pool() -> None:
    global redis_pool
    redis_pool = redis.ConnectionPool.from_url("redis://localhost", max_connections=10, decode_responses=True)

It should fix your Exception.

clmnin commented 2 years ago

Thank you.