Skip to content
This repository has been archived by the owner on Dec 30, 2019. It is now read-only.

Race condition in pool.on('connect',...) ? #97

Open
claytongulick opened this issue Feb 20, 2018 · 8 comments
Open

Race condition in pool.on('connect',...) ? #97

claytongulick opened this issue Feb 20, 2018 · 8 comments

Comments

@claytongulick
Copy link

A (fairly) common question I see around is how to set options like search_path with node-pg. The answer I see most commonly given is to use something like

pool.on('connect', (client) => {client.query('set search_path...');});

Glancing through the code though, it doesn't look like doing this will actually guarantee that the search_path will be set before a client issues a query, given that it's an async call.

Are we running the risk that queries can be executed prior to setup? This could be a potential security issue as well if using RLS and something like 'SET my.user_id = 123' - a query could potentially be executed prior to the SET command completing?

@charmander
Copy link
Collaborator

charmander commented Feb 20, 2018

Event listeners are called synchronously by emit, and the pool emits connect on a client before the client is used, so if the listener makes a query immediately (like here) there’s no race condition compared to queries after the client has been acquired. It’s not an elegant solution, however, and the query queue that allows this to work is a bit of a pain – which is why I’d prefer to expose brianc/node-postgres#1393 (comment).

@claytongulick
Copy link
Author

@charmander I glanced through the source, and given that the db call is async, I didn't see any guarantee that a call like I have in my example would complete prior to a client issuing a query. Did I miss something?

@charmander
Copy link
Collaborator

@claytongulick A client can only run one query at a time, so pg keeps a queue of queries for each client. If the query is first to enter the queue, it will be the first to run.

@msakrejda
Copy link

Thanks for clarifying that @charmander -- I came here with the same concern as @claytongulick and found this issue, but what you're saying makes sense.

@mathroc
Copy link

mathroc commented Jun 8, 2018

it's true that you can guarantee the query to be executed first, but, only if the connect callback is synchronous, if your callback uses await/promises before issuing the query, the order won't be guaranteed

I'm currently looking for a workaround for this

also, I think sometimes (eg, for SET my.user_id = 123) I think the correct event to listen to is acquire because the pool could potentially return an already connected client (despite the function being called connect). to be confirmed, I'm not 100% certain

@mathroc
Copy link

mathroc commented Jun 8, 2018

well there is the undocumented options.verify that could be used for on connect, but it won't work for acquired: options.verify is only called for new clients and not when they are reused.

so I resorted to monkey patching the connect method for now

@charmander
Copy link
Collaborator

@mathroc What is it that you need to do every time a connection is acquired?

@mathroc
Copy link

mathroc commented Jun 8, 2018

it's a websocket application, I call select set_config('session.id', $1::text, false) with the session id corresponding to socket I'm working with (it's used by row level security rules)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants