Debugging Turbo::Streams::BroadcastJob only working with inline/async

I am really excited to be incorporating broadcast_render_to/broadcast_render_later_to to render turbo stream partials and seeing it all mostly “just work” across all open browsers.

Even though the partials are very small/simple, I figured I’d try to use the later version to kick these off to a job to see how it performs, and I’m pretty stumped at the moment, because every Turbo::Streams::BroadcastJob job finishes successfully regardless of which queue adapter I use, but the web socket in the browser only actually receives a message if it’s sent via the inline or async adapters. Using solid_queue shows the jobs themselves succeeding almost instantly but no messages ever make it to the browser.

Any ideas on how to debug / troubleshoot this?

In my model:

after_update_commit -> {
  broadcast_render_later_to(user, id, :player,
    partial: "player/progress_update")
}

I don’t think it has to do with any assumptions about data, since the partial could literally be plain text and it still doesn’t send:

<%= turbo_stream.replace "player" do %>
  BOOM SHAKALAKA
<% end %>

Any help would be greatly appreciated!

Welp, this was my own damn fault for forgetting ActionCable subscription information has to be stored somewhere if you’re going to use an outside-of-process queue adapter.

Explanataion:

I did a little digging into turbo-rails’ source and I got this far with both :async and :solid_queue looking the same until you look at the state of the ActionCable.server

# app/channels/turbo/streams/broadcasts.rb
def broadcast_stream_to(*streamables, content:)
  streamables.flatten!
  streamables.compact_blank!

  if streamables.present?
    ActionCable.server.broadcast stream_name_from(streamables), content
    # > ActionCable.server.connections
    # :async => [#<ApplicationCable::Connection:0x0000000002cd30>, #<ApplicationCable::Connection:0x0000000002cd58>]
    # :solid_queue => []
  end
end

So only async has ActionCable subscriptions…… :man_facepalming: of course it does, because the default ActionCable configuration only has an async subscription adapter configured:

# config/cable.yml
development:
  adapter: async

So, lesson learned. If you want to use a real queue adapter for Active Job in development, you need to use a real subscription adapter for Action Cable too!

1 Like

Huh, this is indeed strange! I wonder if when running on adapters other than inline or async, the job is failing in reality but with an error that gets automatically discarded, given the impression that it went all well, but it did nothing? ActiveJob::DeserializationError comes to mind, as it’s discarded by default :thinking:

Oops, we posted at the same time! :sweat_smile::sweat_smile: Great find and great lesson; I hadn’t thought about that at all!

1 Like