提交 d2571e56 编写于 作者: J justin talbott 提交者: Jeremy Daer

add rescue_with support to ActionCable::Connection::Base

and update ActionCable guide to describe exception handling usage

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is behind 'origin/master' by 5 commits, and can be fast-forwarded.
#
# Changes to be committed:
#	modified:   actioncable/CHANGELOG.md
#	modified:   actioncable/lib/action_cable/connection/base.rb
#	modified:   actioncable/lib/action_cable/connection/subscriptions.rb
#	modified:   actioncable/test/connection/subscriptions_test.rb
#	modified:   guides/source/action_cable_overview.md
#
上级 5df9b458
* `ActionCable::Connection::Base` now allows intercepting unhandled exceptions
with `rescue_from` before they are logged, which is useful for error reporting
tools and other integrations.
*Justin Talbott*
* Add `ActionCable::Channel#stream_or_reject_for` to stream if record is present, otherwise reject the connection
*Atul Bhosale*
......
# frozen_string_literal: true
require "action_dispatch"
require "active_support/rescuable"
module ActionCable
module Connection
......@@ -46,6 +47,7 @@ class Base
include Identification
include InternalChannel
include Authorization
include ActiveSupport::Rescuable
attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol
delegate :event_loop, :pubsub, to: :server
......
......@@ -21,6 +21,7 @@ def execute_command(data)
logger.error "Received unrecognized command in #{data.inspect}"
end
rescue Exception => e
@connection.rescue_with_handler(e)
logger.error "Could not execute command from (#{data.inspect}) [#{e.class} - #{e.message}]: #{e.backtrace.first(5).join(" | ")}"
end
......
......@@ -3,12 +3,25 @@
require "test_helper"
class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase
class ChatChannelError < Exception; end
class Connection < ActionCable::Connection::Base
attr_reader :websocket
attr_reader :websocket, :exceptions
rescue_from ChatChannelError, with: :error_handler
def initialize(*)
super
@exceptions = []
end
def send_async(method, *args)
send method, *args
end
def error_handler(e)
@exceptions << e
end
end
class ChatChannel < ActionCable::Channel::Base
......@@ -22,6 +35,10 @@ def subscribed
def speak(data)
@lines << data
end
def throw_exception(_data)
raise ChatChannelError.new("Uh Oh")
end
end
setup do
......@@ -85,6 +102,19 @@ def speak(data)
end
end
test "accessing exceptions thrown during command execution" do
run_in_eventmachine do
setup_connection
subscribe_to_chat_channel
data = { "content" => "Hello World!", "action" => "throw_exception" }
@subscriptions.execute_command "command" => "message", "identifier" => @chat_identifier, "data" => ActiveSupport::JSON.encode(data)
exception = @connection.exceptions.first
assert_kind_of ChatChannelError, exception
end
end
test "unsubscribe from all" do
run_in_eventmachine do
setup_connection
......
......@@ -128,6 +128,27 @@ can use this approach:
verified_user = User.find_by(id: cookies.encrypted['_session']['user_id'])
```
#### Exception Handling
By default, unhandled exceptions are caught and logged to Rails' logger. If you would like to
globally intercept these exceptions and report them to an external bug tracking service, for
example, you can do so with `rescue_with`.
```ruby
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
rescue_from StandardError, with: :report_error
private
def report_error(e)
SomeExternalBugtrackingService.notify(e)
end
end
end
```
### Channels
A *channel* encapsulates a logical unit of work, similar to what a controller does in a
......@@ -175,6 +196,25 @@ class ChatChannel < ApplicationCable::Channel
end
```
#### Exception Handling
As with `ActionCable::Connection::Base`, you can also use
[`rescue_with`](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)
on a specific channel to handle raised exceptions:
```ruby
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
rescue_from 'MyError', with: :deliver_error_message
private
def deliver_error_message(e)
broadcast_to(...)
end
end
```
## Client-Side Components
### Connections
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册