snlamm and I are having an issue with implementing multiple web socket channels in our Rails app. The error is that the server freezes after the response below:
Started GET "/cable" for ::1 at 2016-05-24 11:42:16 -0400
Started GET "/cable/" [WebSocket] for ::1 at 2016-05-24 11:42:16 -0400
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Note: Our browser console throws no errors. We are using Chrome v 50.0 (latest version).
However, on an inconsistent basis if we restart both our browser and server we get:
Started GET "/cable" for ::1 at 2016-05-24 11:45:54 -0400
Started GET "/cable/" [WebSocket] for ::1 at 2016-05-24 11:45:54 -0400
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
ItemsChannel is transmitting the subscription confirmation
ItemsChannel is streaming from items
MessagesChannel is transmitting the subscription confirmation
MessagesChannel is streaming from messages
and everything works fine.
As mentioned this fix is inconsistent and more often than not our server freezes. We have noticed that there are no issues when we only have one channel running.
Here is our code for the items channel, which is one of the two channels we added. The code for both channels are nearly identical:
route
mount ActionCable.server => '/cable'
channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
channels/items_channel.rb
class ItemsChannel < ApplicationCable::Channel
def subscribed
stream_from 'items'
end
end
views/orders/show.html.erb
This is our view for the channel attached to showing an item.
<div id="item-list">
<h2>Items: <% @order.items.each do |item| %></h2>
<li><%= item.name %> - $<%= item.cost %></li>
<% end %>
</div>
</ol>
<div id="item-errors">
</div>
<br>
<h3>Time until ordered: <%= ((@order.expiration - @order.date_ordered) / 60).round %> minutes</h3></div>
<%= form_for @item, remote: true do |f| %>
<%= f.hidden_field :order_id, value: @order.id, id: "order-id" %>
<span id='item-content-reset'>
Item name: <%= f.text_field :name, id: 'item-name' %>
Cost: <%= f.text_field :cost, id: 'item-cost' %>
</span>
<%= f.submit "Add Item", :id => 'item-create-btn' %>
<% end %>
</div>
controllers/items_controller.rb
class ItemsController < ApplicationController
def create
@item = Item.new(item_params)
@item.user = @current_user
if @item.save
ActionCable.server.broadcast 'items',
name: @item.name,
cost: @item.cost
head :ok
else
error_message = @item.errors.messages
render partial: 'shared/errors', locals: { errors: flash.now[:alert] = "Item " + error_message[:name][0] }
end
end
private
def item_params
params.require(:item).permit(:order_id, :cost, :name)
end
end
assets/application.js
//= require jquery
//= require bootstrap-sprockets
//= require jquery_ujs
//= require bootstrap-switch
// require jquery.session
// require turbolinks
//= require_tree .
assets/javascripts/channels/chatrooms.js
//= require action_cable
//= require_self
//= require_tree .
this.App = {};
App.cable = ActionCable.createConsumer("/cable");
assets/javascripts/channels/items.js
App.items = App.cable.subscriptions.create('ItemsChannel', {
received: function(data) {
return $("#item-list").append(this.renderItem(data));
},
renderItem: function(data) {
return "<li> " + data.name + " - " + "$" + data.cost + "</li>";
}
});
After ending the server we ps aux | grep for rails, ruby, puma, redis and they had all closed successfully (i.e. there were no zombie processes). What could be causing the server to freeze?
This sounds like the following bug (Actioncable deadlock with multiple channels #24741). You can get the patch at the preceding link. If you're working in development, you can also try setting config.eager_load = true
in development.rb, which worked for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With