-
-
Notifications
You must be signed in to change notification settings - Fork 623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pool cannot detect idle connection disconnected by MySQL and will trigger read ECONNRESET
on newly acquired connection
#683
Comments
I saw this problem as well, and I think there is no way to automatically detect "server closed connection" automatically other than doing some kind of heartbeat messages Are you sure doing |
I think first step would be adding all events supported by mysqljs/mysql pool - https://github.com/mysqljs/mysql/#release That way you can start/stop heartbeat in your code manually in reponse to And later we could simplify that and make available as pool option |
Thanks for your reply. |
Hi @sidorares , It seems I can't get Here are the code examples (I used generic-pool for pool management): Working Example (use
Non-working Example (use
Before the tests, I changed my local MySQL |
I'm seeing this too, and not only due to About detecting closed connections, I've noticed that the number of free connections (during low-load) matches the number of actual open TCP connections. The There are some notes in this gist. As you can see from the notes, the amount of It seems a pretty serious issue, since after all the connections have been dropped - the pool will never regain any of them, practically stalling all subsequent DB queries until the process is restarted. |
I too was hit with the |
Did some tests today, I couldn't replicate the
mysql2 version 1.5.3. My testing code: const mysql = require('mysql2/promise')
const settings = {
host: 'localhost',
user: 'dbuser',
password: 'password',
database: 'dbname',
connectionLimit: 2
}
const sleep = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
}
const main = async () => {
const pool = await mysql.createPool(settings)
// console.log(pool)
const r = await pool.query('show session variables like "%timeout"')
console.log(r)
const [rowsA, fieldsB] = await pool.query('select * from awesomeTbl')
console.log('to query in 30 seconds')
await sleep(30000)
const [rows, fields] = await pool.query('select * from awesomeTbl')
const [rows2, fields2] = await pool.query('select * from awesomeTbl')
console.log('to query again in 30 seconds')
await sleep(30000)
const [rows1, fields1] = await pool.query('select * from awesomeTbl')
await pool.end()
}
main() None of the queries triggers an error. |
I am seeing this as well, it is a shame too, because mysql2 is so much faster with my DB, alas, I cant have the server throwing ECONNRESET without remedy. |
I have problem with ECONNRESET (mysql, pool, knex, node) and I belive if you have the option to tweak this param on server, it should be ok . . . |
@anthonywebb in one of my recent projects I am being hit with the same problem again and I implemented a quick and dirty solution by querying the mysql server with: setInterval(() => {
pool.query('select 1')
}, 120000) It's ugly but at least it works. |
@midnightcodr How does that ensure that all of the connections in the pool are kept alive? That is, if you have 10 connections in the pool, is it possible that the keep-alive code will simply use the first connection over and over again and let the other 9 die off? |
@benbotto I doubt that's how pooling works. Let's say you specify a pool size of 10, mysql2 (or mysql) does not create or keep 10 connections alive all the time. It only create up to 10 connections when needed. Most of the time you should have fewer than 10 connections alive at the same time - unless your mysql server is mad busy. |
@midnightcodr Sure, that makes sense, but the question still stands. The 10 is arbitrary (and small fries!). Is it possible that your keep-alive code snippet will simply use the first connection over and over again and let the other n connections in the pool die off? Let's say that 2 connections are created in the pool. After idling for a while, these connections are killed by MySQL, potentially due to the So with your keep-alive snippet, will it keep the both connections alive? Or is it possible that only one is kept alive, and the next time that 2 connections are needed the second connection fails with an ECONNRESET error? And thank you for the response and help! |
So there are 2 different questions here: 1) the driver should (ideally) remove connection from the pool immediately after it's killed. 2) A way to prefer to have N hot connections in the pool all the time (and if it gets below that for some reason actively re open new one) Regarding 1 - I previously had issues where network socket does not get any events at all when other end is closed. I need to test that again, if there is a way to see it's closed (ideally without heartbeats and just via os level notification) we should definitely make sure connection is removed from the pool Open to more discussion re question 2 Also if anyone can debug what happens for example when you kill server or kill connection using server side sql that would be helpful ( do we get anything fired here? Line 81 in d8cac2a
Line 67 in d8cac2a
|
Thanks for the response, @sidorares. I don't personally have a need for haveing N hot connections in the pool (2). The case I presented is just a hypothetical, and it's a question about midnightcodr's keep-alive code snippet. But plain and simple: I'm getting ECONNRESET errors and I'm trying to diagnose and solve the problem. |
@benbotto I updated previous comment, can you debug if |
Yes.
Neither https://github.com/benbotto/mysql2-timeout There's what I tried.
Just to be clear, that unfortunately does not reproduce the ECONNRESET error. Edit: db_1_e4e1ba884a68 | 2019-12-11T23:36:46.121358Z 2 [Note] Aborted connection 2 to db: 'timeout' user: 'timeout-user' host: '172.31.0.3' (Got timeout reading communication packets) When I get ECONNRESET errors in my production code, it seems to be accompanied by those same "notes." |
Thanks for repo repo with docker, I might try it later today |
Sorry. Looking at the code in question. After
|
maybe https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay can help ( following answer in https://stackoverflow.com/questions/27356937/how-to-detect-client-side-internet-disconnection-using-node-js ) |
I'm checking in my production system if Thank you for the links. I will read through them and see if keep-alive helps. |
if it helps I'm happy to set it by default or maybe allow to pass as config parameter |
@sidorares Long night getting this fixed. In my case the ECONNRESET errors are not due to
A few questions then:
Again, sorry to hijack this thread. At a glance it looked like the same issue as I was encountering. You got me pointed in the right direction yesterday, and I appreciate the help and the great library! |
@benbotto I am very interested in how you set Net.Socket#setKeepAlive with mysql2. Can you share some code snippet? I suspect some modification to mysql2 lib is required? |
Sure thing, @midnightcodr. Here's the change: benbotto@0943dee I'm not familiar with the mysql2 code, so I don't know if this changes works in all scenarios. Note that just above the change there are a few branches in the code--different ways that |
Thanks @benbotto! |
@benbotto since you proved Few thing to note:
Probably just adding a test |
All right, @sidorares, I added a PR. The PR includes two new configuration parameters: |
@midnightcodr published as v2.1.0 |
…ted mysql2 feature, see sidorares/node-mysql2#683
You should probably link to this issue in the comments in the code - or at least explain the need for Edit: It seems the version I have suffers from #1229 which means that this probably won't solve the problem for me. My promises resolve (no errors) with all the expected rows that I select, but with every field set to 0 or null. It happens randomly and I can't reliably reproduce it. |
MySQL will disconnect idle connections after certain time frame.
This time frame is determined by MySQL variable
wait_timeout
.It seems mysql2's pool implementation cannot detect this type of disconnection (ping is not sufficient).
And when it happens, any queries sent through the acquired connection will trigger a
read ECONNRESET
error.At this moment, I have to send a
SELECT 1
query to test the acquired connection before use.And previous code that calls pool.query directly will have to be re-written.
Can Mysql2 provides two extra pool creation options:
SELECT 1
query to test connections in the pool.true
, the pool will test a connection in the pool everyverifyConnectionInterval
seconds.The text was updated successfully, but these errors were encountered: