skip to Main Content

I am facing, "Error: Socket already opened issue" when I am using Redis along with my node.js project.

I am trying to cache database results into Redis cache.. When Redis key is not empty, I will pick records from Redis Key. When its empty, I will pick from DB and set to Redis Key.

Here is my code:

const { response } = require('express');
var express = require('express');
var mysql = require('mysql');
const redis = require('redis');
const client = redis.createClient();

function GetLatestPosts() {
    return new Promise(async function(resolve, reject) {
        await client.connect();
        const value = await client.get('indexitems');
        if (value != null) {
            await client.disconnect();
            resolve(JSON.parse(value));
        }
        else {
            var PostsList;
            mysqldb.getConnection(function (err, connection) {
                var sql = "CALL PRC_GetPostsList()";
                connection.query(sql, async function (err, data, fields) {
                    if (err) throw err;
                    PostsList = data[0];
                    await client.set('indexitems', JSON.stringify(PostsList));
                    await client.expire('indexitems', 86400);
                    await client.disconnect();
                    resolve(PostsList);  
                });
            });
        }
    })
}

I am facing "Error: Socket already opened issue" randomly. Some times it works without any issue. Some times it shows Error: Socket already opened.

Please help me to resolve this issue. Thanks.

Here is my complete error:

Error: Socket already opened
RedisSocket.connect (/home/ubuntu/Projects/Site/Web/node_modules/@node-redis/client/dist/lib/client/socket.js:48:19)
Commander.connect (/home/ubuntu/Projects/Site/Web/node_modules/@node-redis/client/dist/lib/client/index.js:156:70)
/home/ubuntu/Projects/Site/Web/routes/index.js:224:22
new Promise (<anonymous>)
GetPostItems (/home/ubuntu/Projects/Site/Web/routes/index.js:223:12)
/home/ubuntu/Projects/Site/Web/routes/index.js:23:29
Layer.handle [as handle_request] (/home/ubuntu/Projects/Site/Web/node_modules/express/lib/router/layer.js:95:5)
next (/home/ubuntu/Projects/Site/Web/node_modules/express/lib/router/route.js:137:13)
Route.dispatch (/home/ubuntu/Projects/Site/Web/node_modules/express/lib/router/route.js:112:3)
Layer.handle [as handle_request] (/home/ubuntu/Projects/Site/Web/node_modules/express/lib/router/layer.js:95:5)

2

Answers


  1. The problem occurs as client.connect() is called, whereas the redis client is already connected.

    Whenever client.get('indexitems') returns a value, then the connection is correctly closed by await client.disconnect();

    However, if there is no value, then an asynchronous call to mySQL is made, and the disconnection is only made in the callback of that request.

    As this mySQL call happens asynchronously, the function GetLatestPosts may be executed again before the redis connection is closed, and client.connect() called a second time, provoking the error.

    Solution

    The connection to the redis client might be opened only once when the server starts, and kept opened.

    This reduce the overhead of opening a new one at each request, then closing it.

    The adapted code might then look like below:

    const { response } = require('express');
    var express = require('express');
    var mysql = require('mysql');
    const redis = require('redis');
    const client = redis.createClient();
    
    async function start() {
    
        await client.connect();
    
        function GetLatestPosts() {
            return new Promise(async function(resolve, reject) {
                const value = await client.get('indexitems');
                if (value != null) {
                    resolve(JSON.parse(value));
                }
                else {
                    var PostsList;
                    mysqldb.getConnection(function (err, connection) {
                        var sql = "CALL PRC_GetPostsList()";
                        connection.query(sql, async function (err, data, fields) {
                            if (err) throw err;
                            PostsList = data[0];
                            await client.set('indexitems', JSON.stringify(PostsList));
                            await client.expire('indexitems', 86400);
                            resolve(PostsList);  
                        });
                    });
                }
            })
        }
    }
    
    start()
    

    Extra remarks:

    1. A graceful shutdown of the server might also be implemented, in order to close the connections to DB clients in a clean way.
    2. Same goes for the mysql connection: it can be opened only once at server startup.
    3. You might prefer to call client.quit() rather than client.disconnect(), in order to ensure that all commands get executed – as documented.
    Login or Signup to reply.
  2. npm install ioredis works well for serverless applications rather than the native package.!

    https://www.npmjs.com/package/ioredis

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search