Node-postgres: RangeError: Maximum call stack size exceeded

Created on 22 Oct 2019  路  7Comments  路  Source: brianc/node-postgres

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.

All 7 comments

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KeynesYouDigIt picture KeynesYouDigIt  路  3Comments

chovy picture chovy  路  3Comments

joaquimknox picture joaquimknox  路  3Comments

AhmedBHameed picture AhmedBHameed  路  3Comments

tonylukasavage picture tonylukasavage  路  4Comments