Method: EventMachine.defer

Defined in:
lib/eventmachine.rb

.defer(op = nil, callback = nil, errback = nil, &blk) ⇒ Object

EventMachine.defer is used for integrating blocking operations into EventMachine's control flow. The action of defer is to take the block specified in the first parameter (the "operation") and schedule it for asynchronous execution on an internal thread pool maintained by EventMachine. When the operation completes, it will pass the result computed by the block (if any) back to the EventMachine reactor. Then, EventMachine calls the block specified in the second parameter to defer (the "callback"), as part of its normal event handling loop. The result computed by the operation block is passed as a parameter to the callback. You may omit the callback parameter if you don't need to execute any code after the operation completes. If the operation raises an unhandled exception, the exception will be passed to the third parameter to defer (the "errback"), as part of its normal event handling loop. If no errback is provided, the exception will be allowed to blow through to the main thread immediately.

Caveats

Note carefully that the code in your deferred operation will be executed on a separate thread from the main EventMachine processing and all other Ruby threads that may exist in your program. Also, multiple deferred operations may be running at once! Therefore, you are responsible for ensuring that your operation code is threadsafe.

Don't write a deferred operation that will block forever. If so, the current implementation will not detect the problem, and the thread will never be returned to the pool. EventMachine limits the number of threads in its pool, so if you do this enough times, your subsequent deferred operations won't get a chance to run.

The threads within the EventMachine's thread pool have abort_on_exception set to true. As a result, if an unhandled exception is raised by the deferred operation and an errback is not provided, it will blow through to the main thread immediately. If the main thread is within an indiscriminate rescue block at that time, the exception could be handled improperly by the main thread.

Examples:


operation = proc {
  # perform a long-running operation here, such as a database query.
  "result" # as usual, the last expression evaluated in the block will be the return value.
}
callback = proc {|result|
  # do something with result here, such as send it back to a network client.
}
errback = proc {|error|
  # do something with error here, such as re-raising or logging.
}

EventMachine.defer(operation, callback, errback)

Parameters:

  • op (#call) (defaults to: nil)

    An operation you want to offload to EventMachine thread pool

  • callback (#call) (defaults to: nil)

    A callback that will be run on the event loop thread after operation finishes.

  • errback (#call) (defaults to: nil)

    An errback that will be run on the event loop thread after operation raises an exception.

See Also:



1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
# File 'lib/eventmachine.rb', line 1044

def self.defer op = nil, callback = nil, errback = nil, &blk
  # OBSERVE that #next_tick hacks into this mechanism, so don't make any changes here
  # without syncing there.
  #
  # Running with $VERBOSE set to true gives a warning unless all ivars are defined when
  # they appear in rvalues. But we DON'T ever want to initialize @threadqueue unless we
  # need it, because the Ruby threads are so heavyweight. We end up with this bizarre
  # way of initializing @threadqueue because EventMachine is a Module, not a Class, and
  # has no constructor.

  unless @threadpool
    @threadpool = []
    @threadqueue = ::Queue.new
    @resultqueue = ::Queue.new
    spawn_threadpool
  end

  @threadqueue << [op||blk,callback,errback]
end