Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow methods + lambdas for on_error callbacks / middleware #661

Closed
odlp opened this issue Jun 3, 2021 · 3 comments
Closed

Allow methods + lambdas for on_error callbacks / middleware #661

odlp opened this issue Jun 3, 2021 · 3 comments
Labels
duplicate Closed as feature/bug is a duplicate feature request Request for a new feature

Comments

@odlp
Copy link
Contributor

odlp commented Jun 3, 2021

Description

Recently I used add_on_error to add a callback, and incorrectly assumed I could use a Method interchangeably with a proc, e.g:

Bugsnag.configure do |config|
  config.add_on_error(Bugsnag::SomeCallback.method(:process))
end

This ended up breaking the middleware stack, because an exception was thrown. I missed the warnings emitted:

Bugsnag middleware error: undefined method `new' for #<Method:0x00007fdfc70f7b30>

The reason I'd like to use a class here is it's easier to unit test. The solution ended up being to wrap this in a proc:

Bugsnag.configure do |config|
  config.add_on_error(proc { |report| Bugsnag::SomeCallback.process(report) })
end

Describe the solution you'd like

Could middlewares be partitioned whether they respond_to?(:call)? This would provide middleware implementors the option of providing a proc, lambda or method.

Quick, incomplete example:

diff --git a/lib/bugsnag/middleware_stack.rb b/lib/bugsnag/middleware_stack.rb
index d9dcd95..b083d2f 100644
--- a/lib/bugsnag/middleware_stack.rb
+++ b/lib/bugsnag/middleware_stack.rb
@@ -131,8 +131,8 @@ module Bugsnag
     #
     # @return [Array<Proc>]
     def middleware_procs
-      # Split the middleware into separate lists of Procs and Classes
-      procs, classes = @middlewares.partition {|middleware| middleware.is_a?(Proc) }
+      # Split the middleware into separate lists of Callables (procs, lambdas, methods) and Classes
+      callables, classes = @middlewares.partition {|middleware| middleware.respond_to?(:call) }
 
       # Wrap the classes in a proc that, when called, news up the middleware and
       # passes the next middleware in the queue
@@ -140,12 +140,12 @@ module Bugsnag
         proc {|next_middleware| middleware.new(next_middleware) }
       end
 
-      # Wrap the list of procs in a proc that, when called, wraps them in an
+      # Wrap the list of callables in a proc that, when called, wraps them in an
       # 'OnErrorCallbacks' instance that also has a reference to the next middleware
-      wrapped_procs = proc {|next_middleware| OnErrorCallbacks.new(next_middleware, procs) }
+      wrapped_callables = proc {|next_middleware| OnErrorCallbacks.new(next_middleware, callables) }
 
       # Return the combined middleware and wrapped procs
-      middleware_instances.push(wrapped_procs)
+      middleware_instances.push(wrapped_callables)
     end
   end
 end

Following through, OnErrorCallbacks only expects a callback to respond to call:

should_continue = callback.call(report)

Describe alternatives you've considered

Raise an exception (in dev / test?) if anything other than a Proc or Class is passed as a middleware.

Additional context

Happy to contribute a PR if this is judged to be a worthwhile feature.

@yousif-bugsnag
Copy link

Hi @odlp, thanks for raising this!

We like the suggestion as it makes it a bit more ergonomic, and we'd certainly accept a PR if you'd like to submit one?

A couple of things we've noticed:

  • Your current workaround could be made a bit nicer by calling to_proc on the Method:
    config.add_on_error(Bugsnag::SomeCallback.method(:process).to_proc)
  • Lambdas should already be supported since they are Proc objects under the hood.

@yousif-bugsnag yousif-bugsnag added awaiting feedback Awaiting a response from a customer. Will be automatically closed after approximately 2 weeks. feature request Request for a new feature labels Jun 8, 2021
@odlp
Copy link
Contributor Author

odlp commented Jun 11, 2021

Your current workaround could be made a bit nicer by calling to_proc on the Method

Good point, thank you!

PR incoming with the respond_to?(:call) solution.

@yousif-bugsnag yousif-bugsnag added duplicate Closed as feature/bug is a duplicate and removed awaiting feedback Awaiting a response from a customer. Will be automatically closed after approximately 2 weeks. labels Jun 11, 2021
@yousif-bugsnag
Copy link

Closing this in favour of #662

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate Closed as feature/bug is a duplicate feature request Request for a new feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants