mysqljs / mysql

A pure node.js JavaScript Client implementing the MySQL protocol.
MIT License
18.28k stars 2.52k forks source link

Unexpected misuse of transactions, resulting in blocking of query requests #2514

Closed victorykong closed 3 years ago

victorykong commented 3 years ago

Pool options waitForConnections: false, connectionLimit: 5, queueLimit:0

Pool query => getConnection => _enqueueCallback => emit('enqueue') => Emitter return false

When _freeConnections === 0 and _ allconnections > connectionlimit, the callback function will be put in the queue. However, after executing emit('enqueue'), there is no operation, but quietly waiting for the connection to be released or the task to be executed. However, after error handling in the business layer, the query request will not be processed at all, resulting in the phenomenon of suspended animation.

Look at the second screenshot. Why is events an empty object and finally return without any processing? Should MySQL library have some bottom-up processing here? Or at the business level to avoid it?

image

image

dougwilson commented 3 years ago

It s hard to understand what is going on in your example code. What object does ctx.app.mysql refer to? You also cannot await beginTransaction, as this module does not return promises; you have to put the code in the callback if you want it to wait for that query yo complete before proceeding. There is also no such metod as select in this module. Are you using some kind of wrapper around this module? If so, what is it and does the issue still occur if you remove it?

victorykong commented 3 years ago

I'm very sorry, I didn't make myself clear. Egg-MySQL, a plug-in that egg depends on, is used, the dependency relationship is egg-mysql -> ali-rds -> mysql, and the underlying dependency is this library. The problem will not disappear because of removing other dependencies, because the mysql library will be used in the end

image

dougwilson commented 3 years ago

The reason I ask is because your description likes it aound like you called pool.getConnection, but then did not call connection.release. If that happens, the exact behavior you described will happen, as you have to release connections back to the pool in order to use them again. Just with the code you posed, since there is so much indirection to this module and only little bits available to see, I cannot verify this or not.

In order to proceed we qould need to do either one of the following three things:

  1. Provide the full code base you are having trouble with and provide instructions to reproduce the issue.
  2. Provide a minimal reproduction code I can run to see the issue.
  3. You debug the issue and issue a pull request with the fix.
victorykong commented 3 years ago

Yes, as you said, when queueLimit is not set, and commit/rollback (connection. release) is not finally called, it will cause infinite waiting when it is used again.

image