Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5 ActionCable issue with running multiple channels for a web socket

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?

like image 945
J.See Avatar asked Nov 08 '22 14:11

J.See


1 Answers

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.

like image 95
Cleverlemming Avatar answered Jan 04 '23 01:01

Cleverlemming