qc-client-pool
Version:
Pool Querycache connections for Node.js
224 lines (199 loc) • 6.43 kB
JavaScript
/**
* Created by uzysjung on 2016. 3. 16..
*/
;
const qcClient = require('di-qc-client');
const Pool = require('generic-pool').Pool;
const co = require('co');
const _ = require('underscore');
const internals = {};
exports = module.exports = internals.qcPool = function(option,url,id,pass) {
var property = {
name : 'QueryCache',
create : function(callback) {
co( function*(){
try {
var qc = new qcClient();
var connected = yield qc.open(url, id, pass);
} catch(e) {
callback(e);
}
if(connected) {
callback(null,qc);
} else {
callback(new Error("qc is not connected"));
}
});
},
destroy : function(connection) {
co(function*(){
// console.log("QC Pool destroy called");
yield connection.close();
}).catch(function(e){
console.error("QC Pool destroy error occured :",e.stack);
});
},
validate : function(connection) {
if(connection.connectionError) {
console.log('error remove on validate',connection.connectionError);
return false;
}
return true;
},
min: 2,
max: 10,
idleTimeoutMillis: 30000,
queryTimeout : 5000 //5 sec
};
property =_.extend(property,option);
this.pool = new Pool(property);
};
internals.qcPool.prototype.acquire = function() {
const self = this;
return new Promise(function(resolve,reject){
self.pool.acquire(function(err,connection){
if(err) reject(err);
resolve(connection);
});
});
};
//terminate all the resources in the pool
internals.qcPool.prototype.drain = function() {
this.pool.destroyAllNow();
};
internals.qcPool.prototype.getPoolSize = function(){
return this.pool.getPoolSize();
};
internals.qcPool.prototype.getName = function(){
return this.pool.getName();
};
internals.qcPool.prototype.getAvailableConnectionsCount = function() {
return this.pool.availableObjectsCount();
};
internals.qcPool.prototype.getWaitingClientsCount = function() {
return this.pool.waitingClientsCount();
};
internals.qcPool.prototype.getMaxPoolSize= function() {
return this.pool.getMaxPoolSize();
};
internals.qcPool.prototype.query = function(client,sql,option) {
var self = this;
let fn = co(function*(){
let resultSet,stmt, err;
let results = [];
let cbErr;
try {
cbErr = function(conn_error) {
throw conn_error;
};
client.connection.on('error',cbErr);
stmt = client.createStatement();
let hasResultSet = yield stmt.execute(sql);
if (!hasResultSet) {
throw new Error("query affected " + stmt.updateRowCount + " rows.");
}
resultSet = yield stmt.getResultSet();
if (resultSet == null) {
throw new Error("query has no result set. (BUG?)");
}
let rows = 0;
for(;;) {
const nextRowAvailable = yield resultSet.next();
if (nextRowAvailable) {
rows++;
if(option && option.rowResultType == "Dictionary")
results.push(resultSet.getRowDict());
else
results.push(resultSet.getRowArray());
}
else {
break;
}
}
} catch(e) {
err = e;
} finally {
if (resultSet) {
yield resultSet.close();
}
if (stmt) {
yield stmt.close();
}
if(cbErr && client.connection)
client.connection.removeListener('error',cbErr);
if(err) throw err;
}
return results;
});
function timeout(interval) {
return new Promise(function (resolve, reject) {
setTimeout(function(){
reject(new Error('timeout: exceed ' + interval + 'ms'));
}, interval || 0);
})
};
let queryTimeout = self.pool._factory.queryTimeout;
if(option && option.queryTimeout) {
queryTimeout = option.queryTimeout;
}
return co( function*() {
let results,err;
try {
results = yield Promise.race([timeout(queryTimeout),fn]);
} catch(e){
client.connectionError = e;
err = e ;
console.error('qcPool Query Error',e.stack);
} finally {
self.pool.release(client);
if(err) throw err;
}
return results;
});
};
internals.qcPool.prototype.queryUpsert = function(client,sql) {
var self = this;
let fn = co(function*(){
let result,stmt,err,cbErr;
try {
cbErr = function(conn_error) {
throw conn_error;
};
client.connection.on('error',cbErr);
stmt = client.createStatement();
let hasResultSet = yield stmt.execute(sql);
result = yield stmt.setCommit();
} catch(e){
err = e ;
} finally {
if(stmt) {
yield stmt.close();
}
if(cbErr && client.connection)
client.connection.removeListener('error',cbErr);
if(err) throw err;
}
return result;
});
function timeout(interval) {
return new Promise(function (resolve, reject) {
setTimeout(function(){
reject(new Error('timeout: exceed ' + interval + 'ms'));
}, interval || 0);
})
};
return co(function*(){
let result,error;
try {
result = yield Promise.race([timeout(self.pool._factory.queryTimeout),fn])
} catch (e){
client.connectionError = e;
console.error('qcPool Query Error :',e.stack);
error = e;
} finally {
self.pool.release(client);
if(error) throw error;
}
return result;
});
};