yiisoft / yii2-redis

Yii 2 Redis extension.
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
451 stars 184 forks source link

Multiple redis connections with different databases via socket make read/write to the last connected database #260

Closed lemarweb closed 1 year ago

lemarweb commented 1 year ago

What steps will reproduce the problem?

  1. Configure connections like this:
'redisCacheConnection' => [
    'class' => 'yii\redis\Connection',
    'unixSocket' => '/var/run/redis/redis-server.sock',
    'socketClientFlags' => STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT,
    'database' => 0,
],
'redisQueueConnection' => [
    'class' => 'yii\redis\Connection',
    'unixSocket' => '/var/run/redis/redis-server.sock',
    'socketClientFlags' => STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT,
    'database' => 1,
],

For example it can be used to separate cache and queue databases.

'redisCache' => [
    'class' => 'yii\redis\Cache',
    'redis' => 'redisCacheConnection',
    'keyPrefix' => 'fastcache',
],
'queue' => [
    'class' => 'yii\queue\redis\Queue',
    'redis' => 'redisQueueConnection',
    'attempts' => 3,
],
  1. Write some values in redis via redisCacheConnection and redisQueueConnection:

    Yii::$app->redisCacheConnection->set('key1', 'value1'); // to database 0
    Yii::$app->redisQueueConnection->set('key2', 'value2'); // to database 1
  2. Try to get value by key1 from redisCacheConnection:

    echo Yii::$app->redisCacheConnection->get('key1'); // null instead of 'value1'

What's expected?

I had get a string 'value1' (from db 0 via first connection)

What do you get instead?

I got null (from db 1 via second connection).

Because after opening second connection (redisCacheConnection) any request from any redis connection component is sending to last connected database.

2023-05-26_15-34-57_screenshot

Additional info

For example: If you use redis-cache and redis-queue together, push job to queue and after that flush the cache - all data about jobs will be lost (FLUSHDB will be called on database 1 in redis), but cache will not be flushed.

Q A
Yii vesion 2.0.49-dev
PHP version Any (tested on 7.4 and 8.2)
Operating system Ubuntu 20.04.6 LTS
samdark commented 1 year ago

Any idea about the possible fix?

lemarweb commented 1 year ago

Any idea about the possible fix?

Not sure, but maybe store current database index in static variable in yii\redis\Connection. Update this variable value when execute command 'SELECT'. Check if database changed before get or set data, and execute 'SELECT index' again if needed.

rob006 commented 1 year ago

Do you still have this problem if you remove socketClientFlags config? I'm using Redis with socket and I haven't noticed any problems, but I'm not using any custom flags.

rob006 commented 1 year ago

This is issue with STREAM_CLIENT_PERSISTENT flag and it is documented: https://www.yiiframework.com/extension/yiisoft/yii2-redis/doc/api/2.0/yii-redis-connection#$socketClientFlags-detail

lemarweb commented 1 year ago

STREAM_CLIENT_PERSISTENT

Well, actually useful warning. Although, I think it is a bit strange behavior...

Another way to "fix" the problem in my case is using single redis connection for queue and cache, but with shareDatabase = true for \yii\redis\RedisCache

Thanks everyone for your replies.