mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fix unsubscribed
server side behavior
Before this commit, the `unsubscribed` callbacks in Action Cable server side channels were never called. This is because when a WebSocket "goodbye" message was sent from the client, the Action Cable server didn't properly clean up after the now closed WebSocket. This means that memory could possibly skyrocket with this behavior, since part of this commit is to properly remove closed subscriptions from the global subscriptions hash. Say you have 10,000 users currently connected, and then all 10,000 disconnect -- before this patch, Action Cable would still hold onto information (and Ruby objects!) for all of these now dead connections.
This commit is contained in:
parent
9671df3ff7
commit
cefcc0f66e
4 changed files with 28 additions and 6 deletions
|
@ -132,11 +132,8 @@ module ActionCable
|
|||
@ready_state = CLOSING
|
||||
@close_params = [reason, code]
|
||||
|
||||
if @stream
|
||||
@stream.shutdown
|
||||
else
|
||||
finalize_close
|
||||
end
|
||||
@stream.shutdown if @stream
|
||||
finalize_close
|
||||
end
|
||||
|
||||
def finalize_close
|
||||
|
|
|
@ -54,7 +54,7 @@ module ActionCable
|
|||
end
|
||||
|
||||
def unsubscribe_from_all
|
||||
subscriptions.each { |id, channel| channel.unsubscribe_from_channel }
|
||||
subscriptions.each { |id, channel| remove_subscription(channel) }
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -3,6 +3,10 @@ class EchoChannel < ActionCable::Channel::Base
|
|||
stream_from "global"
|
||||
end
|
||||
|
||||
def unsubscribed
|
||||
'Goodbye from EchoChannel!'
|
||||
end
|
||||
|
||||
def ding(data)
|
||||
transmit(dong: data['message'])
|
||||
end
|
||||
|
|
|
@ -198,4 +198,25 @@ class ClientTest < ActionCable::TestCase
|
|||
c.close # disappear before read
|
||||
end
|
||||
end
|
||||
|
||||
def test_unsubscribe_client
|
||||
with_puma_server do |port|
|
||||
app = ActionCable.server
|
||||
identifier = JSON.dump(channel: 'EchoChannel')
|
||||
|
||||
c = faye_client(port)
|
||||
c.send_message command: 'subscribe', identifier: identifier
|
||||
assert_equal({"identifier"=>"{\"channel\":\"EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message)
|
||||
assert_equal(1, app.connections.count)
|
||||
assert(app.remote_connections.where(identifier: identifier))
|
||||
|
||||
channel = app.connections.first.subscriptions.send(:subscriptions).first[1]
|
||||
channel.expects(:unsubscribed)
|
||||
c.close
|
||||
sleep 0.1 # Data takes a moment to process
|
||||
|
||||
# All data is removed: No more connection or subscription information!
|
||||
assert_equal(0, app.connections.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue