1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #27577 from maclover7/jm-fix-27547

Action Cable owns database connection, not Active Record
This commit is contained in:
Rafael Mendonça França 2018-06-08 18:21:05 -04:00
commit c07c708cf6
No known key found for this signature in database
GPG key ID: FC23B6D0F1EEE948
2 changed files with 47 additions and 8 deletions

View file

@ -14,7 +14,7 @@ module ActionCable
end end
def broadcast(channel, payload) def broadcast(channel, payload)
with_connection do |pg_conn| with_broadcast_connection do |pg_conn|
pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel_identifier(channel))}, '#{pg_conn.escape_string(payload)}'") pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel_identifier(channel))}, '#{pg_conn.escape_string(payload)}'")
end end
end end
@ -31,14 +31,24 @@ module ActionCable
listener.shutdown listener.shutdown
end end
def with_connection(&block) # :nodoc: def with_subscriptions_connection(&block) # :nodoc:
ar_conn = ActiveRecord::Base.connection_pool.checkout.tap do |conn|
# Action Cable is taking ownership over this database connection, and
# will perform the necessary cleanup tasks
ActiveRecord::Base.connection_pool.remove(conn)
end
pg_conn = ar_conn.raw_connection
verify!(pg_conn)
yield pg_conn
ensure
ar_conn.disconnect!
end
def with_broadcast_connection(&block) # :nodoc:
ActiveRecord::Base.connection_pool.with_connection do |ar_conn| ActiveRecord::Base.connection_pool.with_connection do |ar_conn|
pg_conn = ar_conn.raw_connection pg_conn = ar_conn.raw_connection
verify!(pg_conn)
unless pg_conn.is_a?(PG::Connection)
raise "The Active Record database must be PostgreSQL in order to use the PostgreSQL Action Cable storage adapter"
end
yield pg_conn yield pg_conn
end end
end end
@ -52,6 +62,12 @@ module ActionCable
@listener || @server.mutex.synchronize { @listener ||= Listener.new(self, @server.event_loop) } @listener || @server.mutex.synchronize { @listener ||= Listener.new(self, @server.event_loop) }
end end
def verify!(pg_conn)
unless pg_conn.is_a?(PG::Connection)
raise "The Active Record database must be PostgreSQL in order to use the PostgreSQL Action Cable storage adapter"
end
end
class Listener < SubscriberMap class Listener < SubscriberMap
def initialize(adapter, event_loop) def initialize(adapter, event_loop)
super() super()
@ -67,7 +83,7 @@ module ActionCable
end end
def listen def listen
@adapter.with_connection do |pg_conn| @adapter.with_subscriptions_connection do |pg_conn|
catch :shutdown do catch :shutdown do
loop do loop do
until @queue.empty? until @queue.empty?

View file

@ -39,4 +39,27 @@ class PostgresqlAdapterTest < ActionCable::TestCase
def cable_config def cable_config
{ adapter: "postgresql" } { adapter: "postgresql" }
end end
def test_clear_active_record_connections_adapter_still_works
server = ActionCable::Server::Base.new
server.config.cable = cable_config.with_indifferent_access
server.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN }
adapter_klass = Class.new(server.config.pubsub_adapter) do
def active?
!@listener.nil?
end
end
adapter = adapter_klass.new(server)
subscribe_as_queue("channel", adapter) do |queue|
adapter.broadcast("channel", "hello world")
assert_equal "hello world", queue.pop
end
ActiveRecord::Base.clear_reloadable_connections!
assert adapter.active?
end
end end