Reputation: 2428
When trying run below code I get Unhandled rejection Error: Can't set headers after they are sent when return GetData(); is invoked it starts execution of the function but immediately returns the control back with the error. Observed during debugging.
Basically the code tries to fetch key from MySQL DB if doesn't exist in redis DB
All database and redis related modules are written in separate file so as to reuse it.
somefile.js
var express = require('express');
var router = express.Router();
var dbModules = require('../common/database');
var redisModules = require("../common/redismodule");
function getSettings(request, response)
{
return GetData();
function GetData()
{
return redisModules.GetRedisValue("key")
.then(function (result)
{
if (!result)
return SetData();
else
return result;
})
.then(function (result)
{
response.status(200).send({ value : result });
})
.catch(function (e)
{
response.status(500).send();
};
}
function SetData()
{
return dbModules.executeQuery('query')
.then(function(results)
{
// some code
return 'some_key';
})
.then(function (result)
{
redisModules.setRedisValue('key', result);
});
}
}
database.js
File for handling database connections
var mysql = require('promise-mysql');
pool = mysql.createPool({
host: '',
user: '',
password: '',
database: '',
connectionLimit: 4
});
module.exports = {
getSqlConnection: function()
{
return pool.getConnection().disposer(function(connection)
{
console.log("came here in releasing connection function");
pool.releaseConnection(connection);
});
},
executeQuery: function(sqlQuery)
{
return Promise.using(module.exports.getSqlConnection(), function(connection)
{
return connection.query(sqlQuery)
.then(function(results)
{
return results;
});
});
}
};
redismodule.js
File for handling redis get, set concepts
var Promise = require('bluebird');
var constants = require('../common/contants');
var redisClient; // Global (Avoids Duplicate Connections)
module.exports =
{
OpenRedisConnection : function()
{
if (redisClient == null)
{
redisClient = require("redis").createClient(6379, 'localhost');
}
},
isRedisConnectionOpened : function()
{
if (redisClient && redisClient.connected == true)
{
return true;
}
else
{
if(redisClient)
redisClient.end(); // End and open once more
module.exports.OpenRedisConnection();
return true;
}
},
GetRedisValue: function (key)
{
return new Promise(function (resolve, reject)
{
if(!module.exports.isRedisConnectionOpened())
reject("Redis connection failure");
redisClient.get(key, function (error, result)
{
if (error)
{
reject(error);
}
else
{
if (result == null)
resolve(); // Key not present so create
else
resolve(result);
}
});
});
},
SetRedisValue: function (key, value)
{
return new Promise(function (resolve, reject)
{
if(!module.exports.isRedisConnectionOpened())
reject("Redis connection failure");
redisClient.set(key, value, 'EX', 1000,
function(err,reply)
{
if (reply == 'OK')
resolve(value); // Send the value
else
reject(err);
});
});
}
};
The execution starts when getSettings function is called.
I have just included all the code so that if its correct it might be useful for others.
Corrected Answer
somefile.js
var Promise = require('bluebird');
var dbModules = require('database');
var redisModules = Promise.promisifyAll(require("redismodule"));
async function getSettings(request, response) {
try {
var data = redisModules.GetRedisValue("key");
if (!data)
data = await SetData();
return response.status(200).send({
value: data
});
} catch (error) {
return response.status(500).send({
'error': 'Try after some time'
});
}
function SetData() {
let result = dbModules.executeQuery('query')
return redisModules.setRedisValue('key', result);
}
}
database.js
var mysql = require('promise-mysql');
var pool = mysql.createPool({
host: '',
user: '',
password: '',
database: '',
connectionLimit: 4
});
function getSqlConnection() {
return pool.getConnection().disposer(function (connection) {
console.log("came here in releasing connection function");
pool.releaseConnection(connection);
});
}
module.exports = {
executeQuery: function (sqlQuery) {
return Promise.using(getSqlConnection(), function (connection) {
return connection.query(sqlQuery)
.then(function (results) {
return results;
});
});
}
};
redismodule.js
var redisClient; // Global (Avoids Duplicate Connections)
// Making the below functions are private
function openRedisConnection() {
if (redisClient && redisClient.connected == true) {
return;
} else {
if (redisClient)
redisClient.end(); // End and open once more
redisClient = require("redis").createClient(6379,
process.env.REDIS_URL, {
auth_pass: process.env.REDIS_PASS
});
redisClient.selected_db = 1;
}
}
module.exports = {
GetRedisValue: function (key) {
openRedisConnection();
redisClient.get(key, function (error, result) {
if (error) {
return error;
} else {
if (result)
return result;
else
return null;
}
});
},
SetRedisValue: function (key, value) {
openRedisConnection();
redisClient.set(key, value, 'EX', 1000,
function (err, reply) {
if (reply == 'OK')
resolve(value); // Send the value
else
reject(err);
});
}
};
Upvotes: 0
Views: 1105
Reputation: 19288
This is the way I see it :
somefile.js
var dbModules = require('../common/database');
var redisModules = require("../common/redismodule");
function getSettings(request, response) {
function getData() {
return redisModules.getRedisValue('key')
.then(function (result) {
return result || setData();
});
}
function setData() {
return dbModules.executeQuery('query')
.then(function(results) {
return redisModules.setRedisValue('key', results);
});
}
return getData()
.then(function(result) {
response.status(200).send({ value: result });
}).catch(function (e) {
response.status(500).send();
});
}
database.js
var mysql = require('promise-mysql');
var pool = mysql.createPool({
host: '',
user: '',
password: '',
database: '',
connectionLimit: 4
});
function getSqlConnection() {
return pool.getConnection().disposer(function(connection) {
console.log("came here in releasing connection function");
pool.releaseConnection(connection);
});
}
module.exports = {
'executeQuery': function(sqlQuery) {
return Promise.using(getSqlConnection(), function(connection) {
return connection.query(sqlQuery);
});
}
};
redismodule.js
var Promise = require('bluebird');
var redis = Promise.promisifyAll(require('redis'));
var redisClient = null;
function openRedisConnection() {
if (!redisClient || !redisClient.connected) {
if (redisClient) {
redisClient.end(); // End and open once more
}
redisClient = redis.createClient(6379, process.env.REDIS_URL, {
auth_pass: process.env.REDIS_PASS
});
redisClient.selected_db = 1;
}
return redisClient;
}
module.exports = {
'getRedisValue': function(key) {
return openRedisConnection().getAsync(key); // here we call the promise-returning .getAsync() method, created by Promise.promisifyAll()
},
'setRedisValue': function(key, value) {
return openRedisConnection().setAsync(key, value, 'EX', 1000); // here we call the promise-returning .setAsync() method, created by Promise.promisifyAll()
}
};
My main contributions are in somefile.js
and redismodule.js
. The third module, database.js
has been tidied but nothing more than that.
Things like dbModules.executeQuery('query')
and redisModules.getRedisValue('key')
need to be addressed but I guess you know what you are doing there.
Upvotes: 1