Skip to content

Commit

Permalink
feat: preserve current_socket_id in jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
palkan committed Oct 13, 2023
1 parent 1df3aa1 commit 057cbb5
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 4 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ if File.exist?(local_gemfile)
else
gem 'actioncable', '~> 7.0'
gem 'activerecord'
gem 'activejob'
end

gem 'sqlite3', '~> 1.3'
13 changes: 13 additions & 0 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,19 @@ AnyCable::Rails.broadcasting_to_others do
end
```

You can also pass socket ID explicitly (if obtained from another source):

```ruby
AnyCable::Rails.broadcasting_to_others(socket_id: my_socket_id) do
# ...
end
# or
ActionCable.server.broadcast stream, data, exclude_socket: my_socket_id
````
**IMPORTANT:** AnyCable Rails automatically pass the current socket ID to Active Job, so you can use `broadcast ..., to_others: true` in your background jobs without any additional configuration.

## Development and test

AnyCable is [compatible](compatibility.md) with the original Action Cable implementation; thus you can continue using Action Cable for development and tests.
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails51.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source "https://rubygems.org"

gem "actioncable", "~> 5.1"
gem "activerecord"
gem "activejob"
gem "rspec-rails", "~> 4.0.0"
gem "sqlite3", "~> 1.3"

Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails6.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source "https://rubygems.org"

gem "actioncable", "~> 6.0"
gem "activerecord"
gem "activejob"
gem "rspec-rails", "~> 4.0.0"
gem "sqlite3", "~> 1.4"

Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails60.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source "https://rubygems.org"

gem "actioncable", "~> 6.0.0"
gem "activerecord"
gem "activejob"
gem "rspec-rails", "~> 4.0.0"
gem "sqlite3", "~> 1.4"

Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails7.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source "https://rubygems.org"

gem "actioncable", "~> 7.0"
gem "activerecord"
gem "activejob"
gem "rspec-rails", "~> 4.0.0"
gem "sqlite3", "~> 1.4"

Expand Down
8 changes: 6 additions & 2 deletions lib/anycable/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ def with_broadcast_options(**options)
self.current_broadcast_options = old_options
end

def broadcasting_to_others(&block)
with_broadcast_options(to_others: true, &block)
def broadcasting_to_others(socket_id: nil, &block)
if socket_id
with_socket_id(socket_id) { with_broadcast_options(to_others: true, &block) }
else
with_broadcast_options(to_others: true, &block)
end
end

# Serialize connection/channel state variable to string
Expand Down
7 changes: 6 additions & 1 deletion lib/anycable/rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@ class Railtie < ::Rails::Railtie # :nodoc:
initializer "anycable.socket_id_tracking" do
ActiveSupport.on_load(:action_controller) do
require "anycable/rails/socket_id_tracking"
include AnyCable::Rails::SocketIdTracking
include AnyCable::Rails::SocketIdTrackingController
end

ActiveSupport.on_load(:active_job) do
require "anycable/rails/socket_id_tracking"
include AnyCable::Rails::SocketIdTrackingJob
end
end

Expand Down
25 changes: 24 additions & 1 deletion lib/anycable/rails/socket_id_tracking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module AnyCable
module Rails
module SocketIdTracking
module SocketIdTrackingController
extend ActiveSupport::Concern

included do
Expand All @@ -15,5 +15,28 @@ def anycable_tracking_socket_id(&block)
Rails.with_socket_id(request.headers[AnyCable.config.socket_id_header], &block)
end
end

module SocketIdTrackingJob
extend ActiveSupport::Concern

attr_accessor :cable_socket_id

def serialize
return super unless Rails.current_socket_id

super.merge("cable_socket_id" => Rails.current_socket_id)
end

def deserialize(job_data)
super
self.cable_socket_id = job_data["cable_socket_id"]
end

included do
around_perform do |job, block|
Rails.with_socket_id(job.cable_socket_id, &block)
end
end
end
end
end
7 changes: 7 additions & 0 deletions spec/dummy/app/jobs/broadcast_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class BroadcastJob < ActiveJob::Base
def perform(stream, data, to_others = false)
ActionCable.server.broadcast(stream, data, to_others: to_others)
end
end
1 change: 1 addition & 0 deletions spec/dummy/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative "boot"
require "action_controller/railtie"
require "action_cable/engine"
require "active_job/railtie"
require "global_id/railtie"
require "active_record/railtie"

Expand Down
24 changes: 24 additions & 0 deletions spec/integrations/broadcast_to_others_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,28 @@ def app
)
end
end

context "with background jobs" do
before do
ActiveJob::Base.disable_test_adapter
end

it "pass cable_socket_id to the job" do
AnyCable::Rails.broadcasting_to_others(socket_id: "pagliacci") do
BroadcastJob.perform_later("testo", {kind: "pizza"}, true)
end

# Wait for all jobs to be processed
ActiveJob::Base.queue_adapter.shutdown

expect(AnyCable.broadcast_adapter).to have_received(:raw_broadcast).once
expect(AnyCable.broadcast_adapter).to have_received(:raw_broadcast).with(
[{
stream: "testo",
data: {kind: "pizza"}.to_json,
meta: {exclude_socket: "pagliacci"}
}].to_json
)
end
end
end

0 comments on commit 057cbb5

Please sign in to comment.