feat: async/await redis connection

v1.18.x
Barış Soner Uşaklı 4 years ago
parent 33bf1b0e2c
commit fdfbc90255

@ -1,9 +1,8 @@
'use strict'; 'use strict';
const async = require('async');
const winston = require('winston');
const nconf = require('nconf'); const nconf = require('nconf');
const semver = require('semver'); const semver = require('semver');
const util = require('util');
const session = require('express-session'); const session = require('express-session');
const connection = require('./redis/connection'); const connection = require('./redis/connection');
@ -36,80 +35,48 @@ redisModule.questions = [
]; ];
redisModule.init = function (callback) { redisModule.init = async function () {
callback = callback || function () { }; redisModule.client = await connection.connect(nconf.get('redis'));
redisModule.client = connection.connect(nconf.get('redis'), function (err) {
if (err) {
winston.error('NodeBB could not connect to your Redis database. Redis returned the following error\n' + err.stack);
return callback(err);
}
require('./redis/promisify')(redisModule.client); require('./redis/promisify')(redisModule.client);
callback();
});
}; };
redisModule.createSessionStore = function (options, callback) { redisModule.createSessionStore = async function (options) {
const meta = require('../meta'); const meta = require('../meta');
const sessionStore = require('connect-redis')(session); const sessionStore = require('connect-redis')(session);
const client = connection.connect(options); const client = await connection.connect(options);
const store = new sessionStore({ const store = new sessionStore({
client: client, client: client,
ttl: meta.getSessionTTLSeconds(), ttl: meta.getSessionTTLSeconds(),
}); });
return store;
if (typeof callback === 'function') {
callback(null, store);
}
}; };
redisModule.createIndices = function (callback) { redisModule.checkCompatibility = async function () {
setImmediate(callback); const info = await redisModule.info(redisModule.client);
redisModule.checkCompatibilityVersion(info.redis_version);
}; };
redisModule.checkCompatibility = function (callback) { redisModule.checkCompatibilityVersion = function (version) {
async.waterfall([
function (next) {
redisModule.info(redisModule.client, next);
},
function (info, next) {
redisModule.checkCompatibilityVersion(info.redis_version, next);
},
], callback);
};
redisModule.checkCompatibilityVersion = function (version, callback) {
if (semver.lt(version, '2.8.9')) { if (semver.lt(version, '2.8.9')) {
return callback(new Error('Your Redis version is not new enough to support NodeBB, please upgrade Redis to v2.8.9 or higher.')); throw new Error('Your Redis version is not new enough to support NodeBB, please upgrade Redis to v2.8.9 or higher.');
} }
callback();
}; };
redisModule.close = function (callback) { redisModule.close = async function () {
callback = callback || function () {}; await redisModule.client.async.quit();
redisModule.client.quit(function (err) {
callback(err);
});
}; };
redisModule.info = function (cxn, callback) { redisModule.info = async function (cxn) {
async.waterfall([ if (!cxn) {
function (next) { cxn = await connection.connect(nconf.get('redis'));
if (cxn) {
return setImmediate(next, null, cxn);
} }
connection.connect(nconf.get('redis'), next);
},
function (cxn, next) {
redisModule.client = redisModule.client || cxn; redisModule.client = redisModule.client || cxn;
const infoAsync = util.promisify(cb => cxn.info(cb));
cxn.info(next); const data = await infoAsync();
}, const lines = data.toString().split('\r\n').sort();
function (data, next) { const redisData = {};
var lines = data.toString().split('\r\n').sort();
var redisData = {};
lines.forEach(function (line) { lines.forEach(function (line) {
var parts = line.split(':'); const parts = line.split(':');
if (parts[1]) { if (parts[1]) {
redisData[parts[0]] = parts[1]; redisData[parts[0]] = parts[1];
} }
@ -132,16 +99,13 @@ redisModule.info = function (cxn, callback) {
redisData.used_memory_human = (redisData.used_memory / (1024 * 1024 * 1024)).toFixed(3); redisData.used_memory_human = (redisData.used_memory / (1024 * 1024 * 1024)).toFixed(3);
redisData.raw = JSON.stringify(redisData, null, 4); redisData.raw = JSON.stringify(redisData, null, 4);
redisData.redis = true; redisData.redis = true;
return redisData;
next(null, redisData);
},
], callback);
}; };
redisModule.socketAdapter = function () { redisModule.socketAdapter = function () {
var redisAdapter = require('socket.io-redis'); const redisAdapter = require('socket.io-redis');
var pub = connection.connect(nconf.get('redis')); const pub = connection.connect(nconf.get('redis'));
var sub = connection.connect(nconf.get('redis')); const sub = connection.connect(nconf.get('redis'));
return redisAdapter({ return redisAdapter({
key: 'db:' + nconf.get('redis:database') + ':adapter_key', key: 'db:' + nconf.get('redis:database') + ':adapter_key',
pubClient: pub, pubClient: pub,

@ -9,25 +9,24 @@ const connection = module.exports;
connection.getConnectionOptions = function (redis) { connection.getConnectionOptions = function (redis) {
redis = redis || nconf.get('redis'); redis = redis || nconf.get('redis');
let connOptions = {}; const connOptions = {};
if (redis.password) { if (redis.password) {
connOptions.auth_pass = redis.password; connOptions.auth_pass = redis.password;
} }
if (redis.hasOwnProperty('database')) {
connOptions = _.merge(connOptions, redis.options || {}); connOptions.db = redis.database;
return connOptions; }
return _.merge(connOptions, redis.options || {});
}; };
connection.connect = function (options, callback) { connection.connect = async function (options) {
callback = callback || function () {}; return new Promise(function (resolve, reject) {
options = options || nconf.get('redis'); options = options || nconf.get('redis');
var redis_socket_or_host = options.host; const redis_socket_or_host = options.host;
var cxn;
var callbackCalled = false;
const connOptions = connection.getConnectionOptions(options); const connOptions = connection.getConnectionOptions(options);
if (redis_socket_or_host && redis_socket_or_host.indexOf('/') >= 0) { let cxn;
if (redis_socket_or_host && String(redis_socket_or_host).indexOf('/') >= 0) {
/* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */ /* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */
cxn = redis.createClient(options.host, connOptions); cxn = redis.createClient(options.host, connOptions);
} else { } else {
@ -35,37 +34,23 @@ connection.connect = function (options, callback) {
cxn = redis.createClient(options.port, options.host, connOptions); cxn = redis.createClient(options.port, options.host, connOptions);
} }
const dbIdx = parseInt(options.database, 10);
if (!(dbIdx >= 0)) {
throw new Error('[[error:no-database-selected]]');
}
cxn.on('error', function (err) { cxn.on('error', function (err) {
winston.error(err.stack); winston.error(err.stack);
if (!callbackCalled) { reject(err);
callbackCalled = true;
callback(err);
}
}); });
cxn.on('ready', function () { cxn.on('ready', function () {
if (!callbackCalled) { resolve(cxn);
callbackCalled = true;
callback(null, cxn);
}
}); });
if (options.password) { if (options.password) {
cxn.auth(options.password); cxn.auth(options.password);
} }
var dbIdx = parseInt(options.database, 10);
if (dbIdx >= 0) {
cxn.select(dbIdx, function (err) {
if (err) {
winston.error('NodeBB could not select Redis database. Redis returned the following error\n' + err.stack);
throw err;
}
}); });
} else {
callbackCalled = true;
return callback(new Error('[[error:no-database-selected]]'));
}
return cxn;
}; };
require('../../promisify')(connection);

@ -4,6 +4,7 @@ const util = require('util');
module.exports = function (redisClient) { module.exports = function (redisClient) {
redisClient.async = { redisClient.async = {
quit: util.promisify(redisClient.quit).bind(redisClient),
send_command: util.promisify(redisClient.send_command).bind(redisClient), send_command: util.promisify(redisClient.send_command).bind(redisClient),
exists: util.promisify(redisClient.exists).bind(redisClient), exists: util.promisify(redisClient.exists).bind(redisClient),

@ -165,7 +165,9 @@ async function completeConfigSetup(config) {
nconf.overrides(config); nconf.overrides(config);
const db = require('./database'); const db = require('./database');
await db.init(); await db.init();
if (db.hasOwnProperty('createIndices')) {
await db.createIndices(); await db.createIndices();
}
// Sanity-check/fix url/port // Sanity-check/fix url/port
if (!/^http(?:s)?:\/\//.test(config.url)) { if (!/^http(?:s)?:\/\//.test(config.url)) {

@ -135,7 +135,9 @@ before(async function () {
await db.init(); await db.init();
if (db.hasOwnProperty('createIndices')) {
await db.createIndices(); await db.createIndices();
}
await setupMockDefaults(); await setupMockDefaults();
await db.initSessionStore(); await db.initSessionStore();

Loading…
Cancel
Save