Conversation
| module ActionCable | ||
| module Channel | ||
| module StreamsHandlers | ||
| class Base # :nodoc: |
There was a problem hiding this comment.
Can we move Base's :nodoc: declaration up to StreamHandlers? Same deal with Custom.
| module Channel | ||
| module StreamsHandlers | ||
| class Base # :nodoc: | ||
| attr_reader :channel, :identifier |
There was a problem hiding this comment.
I might be missing something, but is there are any reason why channel and identifier need to be part of the public API? 😬
|
|
||
| def identity_handler | ||
| -> message { message } | ||
| end |
There was a problem hiding this comment.
Refactoring these stream handler factory methods means they're no longer available for overriding in subclasses.
| ActionCable::Channel::StreamsHandlers::Custom.new(self, handler: user_handler, coder: coder) | ||
| else | ||
| default_stream_handler broadcasting, coder: coder | ||
| ActionCable::Channel::StreamsHandlers::Base.new(self) |
There was a problem hiding this comment.
Should check that coder is JSON, too.
| module ActionCable | ||
| module Channel | ||
| module StreamsHandlers | ||
| class Base # :nodoc: |
There was a problem hiding this comment.
This is a specialized no-op stream transmitter for use when there's no user handler and pubsub & transmit coders match. Wouldn't call it a Base transmitter which suggests it's meant for public API and subclassing.
|
|
||
| alias encode decode | ||
| end | ||
| end |
There was a problem hiding this comment.
This is a no-op coder, hence the existing "identity" language. Introducing "null" language ambiguously suggests that it's coding as null/nil or doing null coding.
| def call(message) | ||
| handler.(coder.decode(message)) | ||
| end | ||
| end |
There was a problem hiding this comment.
This isn't inheriting anything substantial from Base—the inheritance relationship is misleading.
| websocket.transmit encode(cable_message) | ||
| def transmit(cable_message, encoded = false) # :nodoc: | ||
| websocket.transmit(encoded ? cable_message : encode(cable_message)) | ||
| end |
There was a problem hiding this comment.
Boolean flags in method signature are a good red flag to investigate.
In this case, we really want a separate API to transmit already-encoded messages. The existing #transmit can invoke that API after encoding its message.
| when "custom" | ||
| DummyEncoder | ||
| when "none" | ||
| nil |
There was a problem hiding this comment.
This boilerplate isn't particular to this test; wouldn't move it.
| def call(message) | ||
| # We can skip message decoding and generate payload in a more simple way | ||
| connection.transmit( | ||
| "{\"identifier\":#{identifier.to_json},\"message\":#{message}}", |
There was a problem hiding this comment.
Should identifier be quoted here? It's an embedded JSON document.
There was a problem hiding this comment.
No, we should call to_json (which adds surrounding quotes and escapes existing quotes), 'cause identifier is a JSON string itself.
| -> (message) do | ||
| transmit handler.(message), via: via | ||
| end | ||
| end |
There was a problem hiding this comment.
Could introduce coder-aware stream handling directly:
def stream_handler(broadcasting, user_handler, coder: nil)
if user_handler
user_stream_handler broadcasting, user_handler, coder: coder
else
default_stream_handler broadcasting, coder: coder
end
end
def user_stream_handler(user_handler, coder: nil)
-> encoded_message { user_handler.(coder.decode(encoded_message)) }
end
def default_stream_handler(broadcasting, coder: nil)
coder ||= ActiveSupport::JSON
via = "streamed from #{broadcasting}"
if coder == ActiveSupport::JSON
-> encoded_message { transmit_encoded encoded_message, coder: coder, via: via }
else
-> encoded_message { transmit coder.decode(encoded_message), via: via }
end
end|
I haven't yet looked in detail, but even in the no-op case, I wonder if we should decode to ensure it's valid JSON before we throw it at clients |
No-op case doesn't mean that the message is JSON-encoded. For example: ActionCable.server.broadcast "test", { x: 1 }, coder: MyYAMLCoderNo-op only requires that message is a string. Nothing more. Kind of stupid re-transmission. |
Add Connection#transmit_encoded and Channel#transmit_encoded. Avoiding unnecessary decoding and logging.
50879f6 to
4eae47a
Compare
|
@jeremy Also, @maclover7 |
|
Is there any news on this? |
|
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Implementation of #26999 proposals.
What have been done:
streams.rbinto separate classesThe benchmark show the following:
So, broadcasting is about 5-6x faster.
/cc @maclover7 @matthewd