Summary
When calling getClient() I keep having issues with this error before I can even execute anything. I don't really understand what client.query.apply(client, arguments) is supposed to be doing so I am not sure how to fix it. I didn't see anything about it in the documents. I guess the next step is to look through the node-postgres code here.
Has anyone seen an error like this before?
Code
const { Pool } = require('pg');
const pool = new Pool({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASS,
port: process.env.DB_PORT
});
module.exports = {
query: (text, params, callback) => { // Single SQL Query
const start = Date.now()
return pool.query(text, params, (err, res) => {
const duration = Date.now() - start
if(err) {
callback(err, res)
} else {
console.log('executed query', { text, duration, rows: res.rowCount })
console.log('params', {params})
console.log('response', {res})
callback(err, res)
}
})
},
getClient: (callback) => { // Multiple SQL Queries
pool.connect((err, client, done) => {
const query = client.query.bind(client)
// monkey patch the query method to keep track of the last query executed
client.query = () => {
client.lastQuery = arguments
client.query.apply(client, arguments)
}
// set a timeout of 5 seconds, after which we will log this client's last query
const timeout = setTimeout(() => {
console.error('A client has been checked out for more than 5 seconds!')
console.error(`The last executed query on this client was: ${client.lastQuery}`)
}, 5000)
const release = (err) => {
// call the actual 'done' method, returning this client to the pool
done(err)
// clear our timeout
clearTimeout(timeout)
// set the query method back to its old un-monkey-patched version
client.query = query
}
callback(err, client, release)
})
}
}
Error
node-backend | /usr/src/service/db/index.js:33
node-backend | client.query.apply(client, arguments)
node-backend | ^
node-backend |
node-backend | RangeError: Maximum call stack size exceeded
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | at Client.client.query (/usr/src/service/db/index.js:33:22)
node-backend | npm ERR! code ELIFECYCLE
node-backend | npm ERR! errno 1
node-backend | npm ERR! [email protected] server: `node server.js`
node-backend | npm ERR! Exit status 1
node-backend | npm ERR!
node-backend | npm ERR! Failed at the [email protected] server script.
node-backend | npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
hi, you just have an endless recursive loop with this lineclient.query.apply(client, arguments). the error has nothing to do with this library. try this instead:
const query = client.query
// monkey patch the query method to keep track of the last query executed
client.query = function(...args) {
client.lastQuery = args
query.apply(this, args)
}
not sure if that's what you want, but at least it'll get rid of the endless loop and allow you to proceed.
@joelmukuthu
I pulled it right from his documentation. https://node-postgres.com/guides/project-structure
So then does his documentation need to be changed?
getClient: (callback) => {
pool.connect((err, client, done) => {
const query = client.query.bind(client)
// monkey patch the query method to keep track of the last query executed
client.query = () => {
client.lastQuery = arguments
client.query.apply(client, arguments)
}
// set a timeout of 5 seconds, after which we will log this client's last query
const timeout = setTimeout(() => {
console.error('A client has been checked out for more than 5 seconds!')
console.error(`The last executed query on this client was: ${client.lastQuery}`)
}, 5000)
const release = (err) => {
// call the actual 'done' method, returning this client to the pool
done(err)
// clear our timeout
clearTimeout(timeout)
// set the query method back to its old un-monkey-patched version
client.query = query
}
callback(err, client, release)
})
}
Yes, the documentation is wrong there. (It also tries to use arguments in an arrow function, and makes bind wrappers on top of other bind wrappers.) Something like this is closer:
const query = client.query
client.query = (...args) => {
client.lastQuery = args
return query.apply(this, args)
}
Ok, thank you all for the help. I couldn't find any information on it before.
I really don't quite understand how this was supposed to work. At first I thought it might be inside his code and then realized it was JavaScript functions. Now I don't have to play with it too much, thank you guys!
Also, do either of you understand how this is supposed to help? What exactly is trying to be done here with the const query and then client.query in getClient()?
I just don't understand what advantage it brings to the code.
I imagine printing out the query upon error might be helpful, but that is all I can think of.
@gemurdock The idea is to centralize all the interactions with this pg module in a single part of your application so that if you need to customize something later it can be done in one place. For example you could add before / after logging to print the SQL, errors, or timing information to the console for debugging.
Without the centralization you'd need to make that change in possibly many different call sites throughout your application.
The code in example is indeed incorrect. There's a couple things on there that should be updated. What it's trying to do is to print an alert if a connection is checked out for more that 5-seconds with the rationale being that it's probably a coding error of a connection not being properly returned to the pool.
@sehrope
Oh I see! I don't quite understand why it has to be so complicated. Ill play with it, thank you!