anycable-rails-core 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/action_cable/subscription_adapter/any_cable.rb +5 -2
- data/lib/anycable/rails/action_cable_ext/broadcast_options.rb +23 -0
- data/lib/anycable/rails/config.rb +5 -1
- data/lib/anycable/rails/middlewares/executor.rb +4 -4
- data/lib/anycable/rails/railtie.rb +45 -2
- data/lib/anycable/rails/socket_id_tracking.rb +42 -0
- data/lib/anycable/rails/version.rb +1 -1
- data/lib/anycable/rails.rb +29 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 713258efa713cd94cb2aa57891bf52f2483732f6e84b918a90d77924bc9d78e2
|
4
|
+
data.tar.gz: 45151b26a79c7ab05ba42629fcbb2c64a147142a39fe8d9eaff54dbce3b905c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d98ee91a26f73b7e9ff7c60820211ddebf53566520903f6ca26be838f4c27fed6f0a2a36787fe3207b569f32881c83efd263517eaa71a5f74bdee00dd61c63ff
|
7
|
+
data.tar.gz: e0a86e5ccbef6d7735f71663a5a9511dc9dd3a7a7df8fa1ffd4e3cccbf653184c0048cbbd22007f21614f4d78f30ee5aa4bb55b275964f1b9b690e3927c27069
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.4.2 (2023-10-15)
|
6
|
+
|
7
|
+
- Print warning if the database pool size is less than RPC pool size. ([@palkan][])
|
8
|
+
|
9
|
+
- Add support for broadcast options (e.g., `exclude_socket`) and `broadcast ..., to_others: true`. ([@palkan][])
|
10
|
+
|
11
|
+
- Add `batch_broadcasts` option to automatically batch broadcasts for code wrapped in Rails executor. ([@palkan][])
|
12
|
+
|
13
|
+
- Fix broadcast logging in Rails 7.1. ([@iuri-gg][])
|
14
|
+
|
5
15
|
## 1.4.1 (2023-09-27)
|
6
16
|
|
7
17
|
- Fix compatibility with Rails 7.1. ([@palkan][])
|
@@ -18,8 +18,11 @@ module ActionCable
|
|
18
18
|
def initialize(*)
|
19
19
|
end
|
20
20
|
|
21
|
-
def broadcast(channel, payload)
|
22
|
-
::AnyCable.
|
21
|
+
def broadcast(channel, payload, **options)
|
22
|
+
options.merge!(::AnyCable::Rails.current_broadcast_options || {})
|
23
|
+
to_others = options.delete(:to_others)
|
24
|
+
options[:exclude_socket] ||= ::AnyCable::Rails.current_socket_id if to_others
|
25
|
+
::AnyCable.broadcast(channel, payload, **options.compact)
|
23
26
|
end
|
24
27
|
|
25
28
|
def subscribe(*)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_cable"
|
4
|
+
|
5
|
+
ActionCable::Server::Base.prepend(Module.new do
|
6
|
+
def broadcast(channel, payload, **options)
|
7
|
+
return super if options.empty?
|
8
|
+
|
9
|
+
AnyCable::Rails.with_broadcast_options(**options) do
|
10
|
+
super(channel, payload)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end)
|
14
|
+
|
15
|
+
ActionCable::Channel::Base.singleton_class.prepend(Module.new do
|
16
|
+
def broadcast_to(target, payload, **options)
|
17
|
+
return super if options.empty?
|
18
|
+
|
19
|
+
AnyCable::Rails.with_broadcast_options(**options) do
|
20
|
+
super(target, payload)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end)
|
@@ -10,10 +10,14 @@ require "anyway/rails"
|
|
10
10
|
# - `persistent_session_enabled` (defaults to false) — whether to store session changes in the connection state
|
11
11
|
# - `embedded` (defaults to false) — whether to run RPC server inside a Rails server process
|
12
12
|
# - `http_rpc_mount_path` (default to nil) — path to mount HTTP RPC server
|
13
|
+
# - `batch_broadcasts` (defaults to false) — whether to batch broadcasts automatically for code wrapped with Rails executor
|
13
14
|
AnyCable::Config.attr_config(
|
14
15
|
access_logs_disabled: true,
|
15
16
|
persistent_session_enabled: false,
|
16
17
|
embedded: false,
|
17
|
-
http_rpc_mount_path: nil
|
18
|
+
http_rpc_mount_path: nil,
|
19
|
+
batch_broadcasts: false,
|
20
|
+
socket_id_header: "X-Socket-ID",
|
21
|
+
disable_rpc_pool_size_warning: false
|
18
22
|
)
|
19
23
|
AnyCable::Config.ignore_options :access_logs_disabled, :persistent_session_enabled
|
@@ -13,16 +13,16 @@ module AnyCable
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def call(method, message, metadata)
|
16
|
+
sid = metadata["sid"]
|
17
|
+
|
16
18
|
if ::Rails.respond_to?(:error)
|
17
19
|
executor.wrap do
|
18
|
-
sid = metadata["sid"]
|
19
|
-
|
20
20
|
::Rails.error.record(context: {method: method, payload: message.to_h, sid: sid}) do
|
21
|
-
yield
|
21
|
+
Rails.with_socket_id(sid) { yield }
|
22
22
|
end
|
23
23
|
end
|
24
24
|
else
|
25
|
-
executor.wrap { yield }
|
25
|
+
executor.wrap { Rails.with_socket_id(sid) { yield } }
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "anycable/rails/action_cable_ext/connection"
|
4
4
|
require "anycable/rails/action_cable_ext/channel"
|
5
5
|
require "anycable/rails/action_cable_ext/remote_connections"
|
6
|
+
require "anycable/rails/action_cable_ext/broadcast_options"
|
6
7
|
|
7
8
|
require "anycable/rails/channel_state"
|
8
9
|
require "anycable/rails/connection_factory"
|
@@ -30,8 +31,8 @@ module AnyCable
|
|
30
31
|
console.level = ::Rails.logger.level if ::Rails.logger.respond_to?(:level)
|
31
32
|
|
32
33
|
# Rails 7.1+
|
33
|
-
if
|
34
|
-
AnyCable.logger
|
34
|
+
if AnyCable.logger.respond_to?(:broadcast_to)
|
35
|
+
AnyCable.logger.broadcast_to(console)
|
35
36
|
else
|
36
37
|
AnyCable.logger.extend(ActiveSupport::Logger.broadcast(console))
|
37
38
|
end
|
@@ -59,6 +60,27 @@ module AnyCable
|
|
59
60
|
::Rails.error.report(ex, handled: false, context: {method: method.to_sym, payload: message})
|
60
61
|
end
|
61
62
|
end
|
63
|
+
|
64
|
+
if AnyCable.config.batch_broadcasts?
|
65
|
+
if AnyCable.broadcast_adapter.respond_to?(:start_batching)
|
66
|
+
app.executor.to_run { AnyCable.broadcast_adapter.start_batching }
|
67
|
+
app.executor.to_complete { AnyCable.broadcast_adapter.finish_batching }
|
68
|
+
else
|
69
|
+
warn "[AnyCable] Auto-batching is enabled for broadcasts but your anycable version doesn't support it. Please, upgrade"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
initializer "anycable.socket_id_tracking" do
|
75
|
+
ActiveSupport.on_load(:action_controller) do
|
76
|
+
require "anycable/rails/socket_id_tracking"
|
77
|
+
include AnyCable::Rails::SocketIdTrackingController
|
78
|
+
end
|
79
|
+
|
80
|
+
ActiveSupport.on_load(:active_job) do
|
81
|
+
require "anycable/rails/socket_id_tracking"
|
82
|
+
include AnyCable::Rails::SocketIdTrackingJob
|
83
|
+
end
|
62
84
|
end
|
63
85
|
|
64
86
|
initializer "anycable.connection_factory", after: "action_cable.set_configs" do |app|
|
@@ -86,6 +108,27 @@ module AnyCable
|
|
86
108
|
end
|
87
109
|
end
|
88
110
|
|
111
|
+
initializer "anycable.verify_pool_sizes" do
|
112
|
+
next if AnyCable.config.disable_rpc_pool_size_warning?
|
113
|
+
# Skip if non-gRPC server is used
|
114
|
+
next unless AnyCable.config.respond_to?(:rpc_pool_size)
|
115
|
+
|
116
|
+
# Log current db vs. gRPC pool sizes
|
117
|
+
AnyCable.configure_server do
|
118
|
+
ActiveSupport.on_load(:active_record) do
|
119
|
+
db_pool_size = ::ActiveRecord::Base.connection_pool.size
|
120
|
+
rpc_pool_size = AnyCable.config.rpc_pool_size
|
121
|
+
|
122
|
+
if rpc_pool_size > db_pool_size
|
123
|
+
::Kernel.warn(
|
124
|
+
"\n⛔️ WARNING: AnyCable RPC pool size (#{rpc_pool_size}) is greater than DB pool size (#{db_pool_size})\n" \
|
125
|
+
"Please, consider adjusting the database pool size to avoid connection wait times and increase throughput of your RPC server\n\n"
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
89
132
|
# Since Rails 6.1
|
90
133
|
if respond_to?(:server)
|
91
134
|
server do
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnyCable
|
4
|
+
module Rails
|
5
|
+
module SocketIdTrackingController
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
around_action :anycable_tracking_socket_id
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def anycable_tracking_socket_id(&block)
|
15
|
+
Rails.with_socket_id(request.headers[AnyCable.config.socket_id_header], &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module SocketIdTrackingJob
|
20
|
+
extend ActiveSupport::Concern
|
21
|
+
|
22
|
+
attr_accessor :cable_socket_id
|
23
|
+
|
24
|
+
def serialize
|
25
|
+
return super unless Rails.current_socket_id
|
26
|
+
|
27
|
+
super.merge("cable_socket_id" => Rails.current_socket_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def deserialize(job_data)
|
31
|
+
super
|
32
|
+
self.cable_socket_id = job_data["cable_socket_id"]
|
33
|
+
end
|
34
|
+
|
35
|
+
included do
|
36
|
+
around_perform do |job, block|
|
37
|
+
Rails.with_socket_id(job.cable_socket_id, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/anycable/rails.rb
CHANGED
@@ -6,6 +6,7 @@ require "anycable/rails/config"
|
|
6
6
|
require "anycable/rails/rack"
|
7
7
|
|
8
8
|
require "globalid"
|
9
|
+
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
9
10
|
|
10
11
|
module AnyCable
|
11
12
|
# Rails handler for AnyCable
|
@@ -14,6 +15,9 @@ module AnyCable
|
|
14
15
|
|
15
16
|
ADAPTER_ALIASES = %w[any_cable anycable].freeze
|
16
17
|
|
18
|
+
thread_mattr_accessor :current_socket_id
|
19
|
+
thread_mattr_accessor :current_broadcast_options
|
20
|
+
|
17
21
|
class << self
|
18
22
|
def enabled?
|
19
23
|
adapter = ::ActionCable.server.config.cable&.fetch("adapter", nil)
|
@@ -24,6 +28,29 @@ module AnyCable
|
|
24
28
|
ADAPTER_ALIASES.include?(adapter)
|
25
29
|
end
|
26
30
|
|
31
|
+
def with_socket_id(socket_id)
|
32
|
+
old_socket_id, self.current_socket_id = current_socket_id, socket_id
|
33
|
+
yield
|
34
|
+
ensure
|
35
|
+
self.current_socket_id = old_socket_id
|
36
|
+
end
|
37
|
+
|
38
|
+
def with_broadcast_options(**options)
|
39
|
+
old_options = current_broadcast_options
|
40
|
+
self.current_broadcast_options = options.reverse_merge(old_options || {})
|
41
|
+
yield
|
42
|
+
ensure
|
43
|
+
self.current_broadcast_options = old_options
|
44
|
+
end
|
45
|
+
|
46
|
+
def broadcasting_to_others(socket_id: nil, &block)
|
47
|
+
if socket_id
|
48
|
+
with_socket_id(socket_id) { with_broadcast_options(to_others: true, &block) }
|
49
|
+
else
|
50
|
+
with_broadcast_options(to_others: true, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
27
54
|
# Serialize connection/channel state variable to string
|
28
55
|
# using GlobalID where possible or JSON (if json: true)
|
29
56
|
def serialize(obj, json: false)
|
@@ -50,9 +77,9 @@ module AnyCable
|
|
50
77
|
end
|
51
78
|
|
52
79
|
module Extension
|
53
|
-
def broadcast(
|
80
|
+
def broadcast(...)
|
54
81
|
super
|
55
|
-
::AnyCable.broadcast(
|
82
|
+
::AnyCable.broadcast(...)
|
56
83
|
end
|
57
84
|
end
|
58
85
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anycable-rails-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anycable-core
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- lib/action_cable/subscription_adapter/anycable.rb
|
67
67
|
- lib/anycable-rails.rb
|
68
68
|
- lib/anycable/rails.rb
|
69
|
+
- lib/anycable/rails/action_cable_ext/broadcast_options.rb
|
69
70
|
- lib/anycable/rails/action_cable_ext/channel.rb
|
70
71
|
- lib/anycable/rails/action_cable_ext/connection.rb
|
71
72
|
- lib/anycable/rails/action_cable_ext/remote_connections.rb
|
@@ -86,6 +87,7 @@ files:
|
|
86
87
|
- lib/anycable/rails/middlewares/log_tagging.rb
|
87
88
|
- lib/anycable/rails/rack.rb
|
88
89
|
- lib/anycable/rails/railtie.rb
|
90
|
+
- lib/anycable/rails/socket_id_tracking.rb
|
89
91
|
- lib/anycable/rails/version.rb
|
90
92
|
- lib/generators/anycable/download/USAGE
|
91
93
|
- lib/generators/anycable/download/download_generator.rb
|