brianmario / mysql2

A modern, simple and very fast Mysql library for Ruby - binding to libmysql
http://github.com/brianmario/mysql2
MIT License
2.25k stars 550 forks source link

"Commands out of sync" exceptions with threads and prepared statements. #1338

Open Math2 opened 12 months ago

Math2 commented 12 months ago

The problem was happening with a connection pool shared by many threads, but I found a simple way to reproduce it:

conf = { ... }

clients = 10.times.map { Mysql2::Client.new(**conf) }

loop do
  clients.map do |client|
    Thread.new { client.prepare("SELECT 123").execute }
  end.each(&:join)
end

This immediately fails with "Commands out of sync; you can't run this command now (Mysql2::Error)" here (after 50 or so iterations of the outer loop).

With #query it works fine. It only fails with prepared statements.

Math2 commented 12 months ago

Oops, actually if you #close the statements, this works fine.

I believe I'm seeing a problem with threads and prepared statements that happens without prepared statements accumulating endlessly like this, but this isn't a way to reproduce it...

Math2 commented 12 months ago

Very curious. This one fails with "Commands out of sync" exceptions while reusing the same prepared statements, but apparently only if the query returns 0 rows!

conf = { ... }

clients = 10.times.map { Mysql2::Client.new(**conf) }
stmts = clients.map { |client| client.prepare("SELECT 123 WHERE FALSE") }

loop do
  stmts.map do |stmt|
    Thread.new { stmt.execute }
  end.each(&:join)
end