node-pg-native
node-pg-native copied to clipboard
query function breaks Promises
Promises work great on regular pg. however, in pg-native, a resolve from a connect works fine, but resolve from query for some reason does not work at all.
here is the simplest test case ( using node --harmony --use_strict test.js):
// test.js
'use strict';
const Client = require('pg-native')
exports.testQuery = function(cl) {
return new Promise( (resolve,reject) => {
cl.query( 'select 1 as col', (err,rows) => {
if( err ) return reject( err );
console.log( 'selected '+rows[0].col );
// resolve is called, but does not get to the then()
resolve( rows[0].col );
});
});
}
exports.testing = function() {
console.log( 'testing' );
let client = new Client();
client.connect( 'port = 6432 dbname = react', err => {
if( err ) return console.log( 'conn err: '+err );
console.log( 'connected' );
exports.testQuery(client)
.then( x => console.log('resolved x='+x) )
.catch( x => console.log( 'err='+x ) );
});
}
exports.testing();
ran same test as above using prepare instead of query and got same results - the Promise's resolve() not passing to the Promise's then()
here is the same test using pg = require('pg').native - this works fine
// test.pg.js
'use strict';
const pg = require('pg').native;
exports.testQuery = function(cl) {
return new Promise( (resolve,reject) => {
cl.query( 'select 1 as col', (err,result) => {
if( err ) return reject( err );
console.log( 'selected '+result.rows[0].col );
resolve( result.rows[0].col );
});
});
}
exports.testing = function() {
console.log( 'testing' );
const connParams = {... };
let client = new pg.Client( connParams );
client.connect( err => {
if( err ) return console.log( 'conn err: '+err );
console.log( 'connected' );
exports.testQuery(client)
.then( x => { console.log('select x='+x); client.end(); } )
.catch( err => { console.log( 'err='+err ); client.end(); } );
});
}
exports.testing();
I don't use promises - care to dive into the code a bit here & see if you can figure out what's causing the issue?
There is something definitely wrong with the client.query function; if the client is ended after the query responds then the promise -- and the http server listen -- work. It may be a bug in node-libpq or in the c library itself. I'll try and isolate it some more.
calling client.pq.stopReader is enough to stop blocking the promise and the http server. Maybe node-libpq needs to have more of the read logic in another thread?
This bug* does not happen on node 0.10.38. It might be some bug in uv_poll_
* At least for the http server example in #21 since promises aren't in node 0.10
for what it's worth, after reporting this, I wrote a new Promise-base node module based on node-libpq, https://github.com/trailsandtribulations/PrPq. the uv_poll code lifted from from node-pg.
it works with no problem, howbeit a bit slower than pg.
On Wed, Jun 3, 2015 at 8:14 AM, Geoff Jacobsen [email protected] wrote:
This bug* does not happen on node 0.10.38. It might be some bug in uv_poll_
- At least for the http server example in #21 https://github.com/brianc/node-pg-native/issues/21 since promises aren't in node 0.10
— Reply to this email directly or view it on GitHub https://github.com/brianc/node-pg-native/issues/16#issuecomment-108149403 .
more testing from my PrPq. Promises no longer work when another service, in this case nodejs-websocket, is enabled. changed consume(): instead of startReader() messaging now using setTimeout() polling. works successfully. heavy load benchmark about the same.
Hmmm...I definitely wouldn't recommend using a setTimeout instead of startReader(). startReader() actually listens on the socket with libuv and gets alerted when the socket actual has data on it. setTimeout is a pretty epic hack....akin to reading of an http server's net socket with setTimeout or something.
Question...does this bug manifest with other versions of promises? Like bluebird or Q or whatever? Not very familiar w/ them but seems strange this hasn't been encountered before.
@jacott are you saying this prevents an http server from binding as well? Do you have an example of this causing an issue without promises?
@brianc see issue #21 for an example
@brianc - have not tried with other Promise systems - running node --harmony --use_strict. assume that, in the end, this stuff will work.
agree that setTimeout() is epic hack. but in the end, once all working, will revert to sanity.
here's the consume() - this is not to say startReader() etc was impeccable to begin with:
PrPq.prototype._consume = () => {
let pq = this;
// if not busy, nothing to consume
if( !pq._conn.libpq.isBusy() ) return Promise.resolve( pq );
// KLUDGE
return new Promise( (resolve,reject) => {
function consume() {
if( !pq._conn.libpq.consumeInput() ) return reject( pq._conn.libpq.errorMessage() );
if( !pq._conn.libpq.isBusy() ) return resolve( pq );
setTimeout( consume );
}
consume();
} );
//
/* startReader() to listen to 'readable' events
return new Promise( (resolve,reject) => {
pq._conn.libpq.startReader();
pq._conn.libpq.on('readable', function() {
// consume input
if( !pq._conn.libpq.consumeInput() ) return reject( pq._conn.libpq.errorMessage() );
// note: consuming a 2nd buffer of input later...
if(pq._conn.libpq.isBusy()) return;
// release listener, stop watcher
//~pq._conn.libpq.removeListener('readable', onReadable);
pq._conn.libpq.removeAllListeners('readable');
pq._conn.libpq.stopReader();
// done
resolve( pq );
});
});
*/
}