Add dynamic environments to callbacks #278

Open
wants to merge 1 commit into from

2 participants

@gdb

This is a pretty alpha patch, but I'm curious whether anyone is interested in this functionality.

My main use-case is for something like the following: an HTTP request is received by an EM server. A series of callbacks happen as backend services are called. An exception is raised in one of them, which bubbles into the global error_handler. At this point, the error_handler would ideally serve a 500 to that request, but it doesn't have enough information to know which pending HTTP request has errored out.

This patch would allow the programmer to store the HTTP request in a dynamic environment, which is accessible from within the error_handler.

@gdb gdb Add a basic dynamic environments implementation
If an exception is raised in the middle of a callback (and not handled
in the callback), the only opportunity the programmer has to deal with
it is in the global error handler. However, in the error handler, the
context in which the error was raised has been lost. With this patch,
callbacks can store values in dynamic environments. If an exception is
raised, the global error handler can access the same dynamic
environment.

USAGE:

'EventMachine::Environment.dynamic_env' returns the current dynamic
env, which can be accessed like a hash.

EXAMPLE:

<<EOF
require 'rubygems'
require 'eventmachine'

EventMachine.error_handler do |er|
  puts "Foo key is #{EventMachine::Environment.dynamic_env[:foo].inspect}"
  EventMachine.stop
end

EventMachine.next_tick do
  EventMachine::Environment.dynamic_env[:foo] = :bar
  raise 'Raised!'
end

EventMachine.run
EOF

CAVEATS:

- This hasn't been tested extensively. I'm sure it doesn't work in
  corner cases. I wouldn't be shocked if it doesn't work in most
  normal cases.

- The code is pretty bad right now. I'll fix it up later once it's
  closer to a final version.
053cdc4
@ibc

Hi, I use a different approach:

My EM server receives a SIP or HTTP request, it's parsed and then the following code is executed:

# _request_ is the Request instance after parsing.

begin
  Logic.process_request(request)
rescue => e
  my_log_error "exception #{e.class}: #{e.message}\n#{(e.backtrace || [])[0..3].join("\n")}"
  request.reply 500, "Internal Error", ["Content-Type: text/plain"], "#{e.class }: #{e.message}"
end
@gdb

What happens if Logic.process_request schedules a callback, and that callback throws an error?

@ibc

You are right, my case is very simplistic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment