From 271ae4023aa67b5d6a4e57d9decebf14479151a2 Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Mon, 5 Feb 2018 17:03:01 -0500 Subject: [PATCH] Close open connections from parent after fork DRb::DRbConn keeps a global pool of open connections which is shared by child processes when they are forked from a parent. If this parent executes a DRb call prior to forking a child process the child picks up this open connection and uses it which can cause replies from the server to go to the wrong DRb client. There is a long standing ruby bug https://bugs.ruby-lang.org/issues/2718 which describes the issue and has reproducer code attached. Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1385038 --- app/models/miq_worker.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/models/miq_worker.rb b/app/models/miq_worker.rb index c0241688fc7..38f34809701 100644 --- a/app/models/miq_worker.rb +++ b/app/models/miq_worker.rb @@ -314,6 +314,7 @@ def self.before_fork def self.after_fork close_pg_sockets_inherited_from_parent DRb.stop_service + close_drb_pool_connections renice(Process.pid) end @@ -330,6 +331,23 @@ def self.close_pg_sockets_inherited_from_parent end end + # Close all open DRb connections so that connections in the parent's memory space + # which is shared due to forking the child process do not pollute the child's DRb + # connection pool. This can lead to errors when the children connect to a server + # and get an incorrect response back. + # + # ref: https://bugs.ruby-lang.org/issues/2718 + def self.close_drb_pool_connections + require 'drb' + + # HACK: DRb doesn't provide an interface to close open pool connections. + # + # Once that is added this should be replaced. + DRb::DRbConn.instance_variable_get(:@mutex).synchronize do + DRb::DRbConn.instance_variable_get(:@pool).each(&:close) + end + end + # Overriding queue_name as now some queue names can be # arrays of names for some workers not just a singular name. # We use JSON.parse as the array of names is stored as a string.