Andrea
Andrea

Reputation: 414

Action Cable Broadcast message fron sidekiq shows up only after refresh, works instantly from console

I followed this tutorial to create an action cable broadcast but it's not quite working as expected. The channel streams and the web app subscribes successfully, but messages broadcasted from the sidekiq background job are only displayed after refreshing the page. Using the same command on the console does result in an immediate update to the page.

When looking at the frames in chrome's developer mode, I cannot see the broadcasted messages from the background job but can immediately see the ones sent by the console. However, I can confirm that the sidekiq background job is broadcasting those messages somewhere since they do show up upon refresh; however, I don't know where they are being queued.

Are there any additional configuration changes needed to keep the messages from the background job from being queued somewhere? Are there any typos or errors in my code that could be causing this?

Action Cable Broadcast message:

ActionCable.server.broadcast "worker_channel", {html:
      "<div class='alert alert-success alert-block text-center'>
        Market data retrieval complete.
    </div>"
    }

smart_worker.rb: -- This is called as perform_async from the controller's action

class SmartWorker
  include Sidekiq::Worker
  include ApplicationHelper
  sidekiq_options retry: false

 def perform
   ActionCable.server.broadcast "worker_channel", {html:
      "<div class='alert alert-success alert-block text-center'>
        Market data retrieval complete.
    </div>"
    }
 end

connection.rb:

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = current_user #find_verified_user ignored until method implemented correctly and does not always return unauthorized
    end

    private 

    def find_verified_user
      if current_user = User.find_by(id: cookies.signed[:user_id]) 
        current_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

worker_channel:

class WorkerChannel < ApplicationCable::Channel
  def subscribed
    stream_from "worker_channel"
  end 

  def unsubscribed
  end
end

worker.js:

App.notifications = App.cable.subscriptions.create('WorkerChannel', {
  connected: function() {
    console.log('message connected');
  },
  disconnected: function() {},
  received: function(data) {
    console.log('message recieved');
    $('#notifications').html(data.html);
  }
});

cable.yml

development:
  adapter: redis
  url: redis://localhost:6379/1

test:
  adapter: async

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: smarthost_production

Also added

to the view but that didn't make a difference.

Upvotes: 4

Views: 2377

Answers (2)

Andrea
Andrea

Reputation: 414

I'm not sure this is the entire explanation but this is what I have observed through further testing:

After multiple server restarts, the broadcast started working and would log as expected in the development logger. Console messages where still hit or miss, so I added some additional identifiers to the broadcasted messages and identified that they were being broadcasted before the loading of the next page was completed. This caused two things: 1) A quick flashing of flash messages triggered by the broadcast (in what was perceived to be the old page - i.e. only works after a refresh) 2) A lack of or inconsistent behavior in the browser console: Because the sidekiq worker job finished so quick, sometimes even before the browser started rendering the new page, I believe the console messages are being reset by the page loading actions and are therefore not visible when you check the logs (or even if you stare at it for a while).

It seems as though this is working as expected, and is simply working to quickly in the local environment which makes it seem as though it's not working as intended.

Upvotes: 1

Vasfed
Vasfed

Reputation: 18454

ActionChannel normally does not queue messages and those broadcasted when there's no subscriber should be lost. Observed behaviour can happen if notification actually comes later than you expect.

I'd check:

  1. Run entire job in console, not just notification, and see if it's running slow
  2. Check sidekiq queues latency
  3. Add logging before/after notification in job and check logs if the job is actually run successfully

Upvotes: 0

Related Questions