From: Robert Klemme Date: 2009-05-21T04:50:59+09:00 Subject: Re: mysql vs. fork On 20.05.2009 15:14, Daniel DeLorme wrote: > It's commonly known that database connections do not play well with > Process.fork; I thought that using at_exit{exit!} was the correct way > to solve this problem, but it appears imperfect. Take this pseudo-code: > > 1 db1 = mysql_connect() > 2 Process.fork do > 3 at_exit{exit!} That line above looks dangerous. After all, what's the point in forcing an exit while we are exiting? > 4 db2 = mysql_connect() > 5 db2.query(...) > 6 end > 7 Process.wait > 8 db1.query(...) > > With line 3, only the at_exit handlers defined in the child process are > run when the child exits, ensuring that db1 stays alive and line 8 keeps > working. Not sure whether that's true. May well be that exit! interrupts the exit handler process... > At least that's what I thought. But in the past 2 days I've been getting > some "MySQL server has gone away" errors from our servers, indicating > that at_exit{exit!} is not enough to protect the db1 connection. It's > not consistently reproducible; I can't get the error when directly > testing but the flow of errormails is unmistakable. So what exactly > was wrong in my understanding of at_exit, sockets, mysql, and fork? The problem with your approach is that your client inherits the DB connection. That's bad because the server thinks he has one peer only. It's not much of an issue if the child does not use the socket but it would be better to close it. Unfortunately you cannot simply close it because you likely won't get access to it as it is buried somewhere in your DB connection class. And if you use the connection's close method chances are that the server shuts down the socket and both clients suffer. You can experiment a bit with these: #!/usr/bin/env ruby19 require 'socket' server = TCPServer.new 7887 client = server.accept client.each do |line| puts line end #!/usr/bin/env ruby19 require 'socket' server = TCPSocket.new '127.0.0.1', 7887 fork do server.puts "child" server.close end sleep 2 server.puts "parent" server.close There is a much simpler solution - just don't inherit the open connection: 2 Process.fork do 4 db2 = mysql_connect() 5 db2.query(...) 6 end 1 db1 = mysql_connect() 7 Process.wait 8 db1.query(...) Btw, it may well be that mysql_connect supports a block so you might be able to write this which is usually safer: fork do mysql_connect do |db| db.query end end mysql_connect do |db| db.query Process.wait db.query end Cheers robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/