ElijahPaul's avatar

Single Redis configuration for both local and production (cluster) environments

How can I configure my Redis configuration in config/database.php to use my local single Redis instance in my local environment and my Redis cluster in production? I feel like I'm missing something obvious.

This configuration works locally:

'redis' => [

        'client' => 'predis',

        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

        'session' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ],

    ],
...

And this is the configuration that works with my production cluster:

'redis' => [

        'client' => 'predis',

        'options' => [
            'cluster' => 'redis',
        ],

        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', 6379),
                    'database' => 0,
                ],
            ],
        ],

        'session' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ],

    ],
...

I want to combine the two (with the help of environment variables?) so my production deployment uses the cluster config and my local dev environment uses my local config/redis instance.

0 likes
17 replies
rameezisrar's avatar

Why are you doing that? Local and Production redis data will, of course, will be different than the production ones

ElijahPaul's avatar

I think I wasn't clear.

I want a single Redis configuration in the database.php file so that when in local my local Redis instance is used, and when in production my Redis cluster is used.

I tried the following:

'redis' => [

        'client' => 'predis',

        'options' => [
            'cluster' => 'cluster' => env('REDIS_CLUSTER', false),
        ],

        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', 6379),
                    'database' => 0,
                ],
            ],
        ],

        'session' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ],

    ],

Thinking that setting my production env variable for REDIS_CLUSTER to redis would mean that the production environment would use the cluster. But that didn't work. I'm confused as to how to achieve this.

rameezisrar's avatar

@elijahpaul

In local .env, use the

APP_NAME=[localProjectName]

and iin your production .env use a different app name

APP_NAME=[ProjectName]

remove clusters from the database.php and it should me like

'redis' => [

        'client' => 'predis',

        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

    ],

and now use Redis based on the app name

Redis::zincrby($this->cacheKey(),1, json_encode([
            'name' => config('app.name'),
            'title' => $thread->title,
            'path' => $thread->path()
        ]));

Now in this way you are storing the different data on local and production and with the same code :)

ElijahPaul's avatar

@rameezisrar thanks for the update.

I tried your suggestion and receive the following error with the Redis cluster environment when running composer:

> @php artisan version:refresh

In Client.php line 370:

  MOVED 6469 10.42.2.97:6379


Script @php artisan version:refresh handling the post-autoload-dump event returned with error code 1

Doesn't removing the 'clusters' cause the above?

rameezisrar's avatar

@elijahpaul your redis array should exactly be like above as I mentioned.

run

sudo composer dump-autoload

If you are storing the redis correctly with the app.name prefix, you won't be having any trouble

ElijahPaul's avatar

@rameezisrar where does this code section go?

Redis::zincrby($this->cacheKey(),1, json_encode([
            'name' => config('app.name'),
            'title' => $thread->title,
            'path' => $thread->path()
        ]));

Also, can I use the APP_ENV instead of the APP_NAME?

Appreciate the help.

rameezisrar's avatar

@elijahpaul Yes, you can use APP_ENV instead of APP_NAME.

Redis::zincrby('any_key_name_for_data',1, json_encode([
            'name' => config('app.name'),
            'title' => $thread->title,
            'path' => $thread->path()
        ]));

this code is just an key and value that I am using to store my data on my local and production redis array

rameezisrar's avatar

@ you can fetch your redis data like this

$data = array_map('json_decode', Redis::zrevrange('key_name', 0, 10)); // get 10 records
ElijahPaul's avatar

@rameezisrar Thank you.

Is there not a way to configure this in the config/database.php file without having to change my code?

i.e. use cluster configuration if APP_ENV=production and default configuration if APP_ENV=local?

Apologies if I've misunderstood (and thanks for your patience).

rameezisrar's avatar

@elijahpaul If you want to use both of them then Wherever you are storing them and fetching them you need to double check. Just follow above and you will be good to go

ElijahPaul's avatar

@rameezisrar OK. I'm definitely really confused..

If I set the following in database.php:

'redis' => [

        'client' => 'predis',

        'options' => [
            'cluster' => 'redis',
        ],

        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', 6379),
                    'database' => 0,
                ],
            ],
        ],

    ],
...

Then composer dump-autoload runs in my Redis cluster environment (APP_ENV=production) without error and without any change to my code:

bash-5.0# sudo composer dump-autoload
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Generating optimized autoload files> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: aws/aws-sdk-php-laravel
Discovered Package: barryvdh/laravel-ide-helper
Discovered Package: creativeorange/gravatar
Discovered Package: fideloper/proxy
Discovered Package: jrean/laravel-user-verification
Discovered Package: laravel/cashier
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: pragmarx/google2fa-laravel
Discovered Package: pragmarx/version
Discovered Package: pragmarx/yaml
Discovered Package: torann/geoip
Discovered Package: yajra/laravel-datatables-oracle
Package manifest generated successfully.
> @php artisan version:refresh
Version was refreshed.
MYAPP version 0.1.2 ALPHA (build cb0c37)                                                                                                  
Generated optimized autoload files containing 4532 classes

Why does the above config work without changing my code?

ElijahPaul's avatar
ElijahPaul
OP
Best Answer
Level 1

Not sure it's the best (right) way of achieving this, but I ended up placing the following logic at the top of my database.php file:

<?php

if (env('APP_ENV') == 'production') {
    $redis =  [
        'client' => 'predis',
        'options' => [
            'cluster' => 'redis',
        ],
        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', 6379),
                    'database' => 0,
                ],
            ],
        ],
    ];
}
else {
    $redis = [
        'client' => 'predis',
        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],
    ];
}

return [

....

And using the follwoing for my redis key:

    'redis' => $redis

So my production environment uses the Redis cluster configuration and my local uses the local config.

1 like
sidscorner's avatar

A bit late, but why don't you just use different array keys instead of an if/else condition?

e.g. redis (default for local and other environments) and redis_cluster for prod?

Then all you have to do is load the correct config from your .env file.

Razdan's avatar

Redis::zincrby($this->cacheKey(),1, json_encode([ 'name' => config('app.name'), 'title' => $thread->title, 'path' => $thread->path() ]));

Where is the destination of this code? Where does it lead to?

ElijahPaul's avatar

@sidscorner This was what I wanted to do in the first place, but (if i remember correctly) I couldn't figure out how to configure redis as the cache driver along with redis_cluster as the prod key.

So I tried the following in my database.php:

'redis' => [
        'client' => 'predis',
        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],
],

'redis_cluster' => [
        'client' => 'predis',
        'options' => [
            'cluster' => 'redis',
        ],
        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', 6379),
                    'database' => 0,
                ],
            ],
        ],
    ];
...

And then had the following in my prod .env;

CACHE_DRIVER=redis_cluster

But redis_cluster wasn't recognized as a redis database connection. If you (or anyone else) know(s) what I'm missing/doing wrong I'd definitely appreciate the help. My solution works, but I'm not comfortable with it.

ElijahPaul's avatar

The thought of adding:

'redis_cluster' => [
            'driver' => 'redis',
        ],

to my config/cache.php file just occurred to me. Will try this later.

localpathcomp's avatar

@ElijahPaul Hello. Having issues with the Follow command from clustering mode. Did you ever figure out a way to make it work cluster mode in prod and non-cluster in lower environments? Never quite understood how to define multiple cluster configs under the the clusters key. I'm assuming you would put in each servers address but with Elasticache theyll be more transient from what I understand? We only need to provide the single config address for the cluster?

Please or to participate in this conversation.