This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
module EventMachine
|
||||
# = EventMachine::ThreadedResource
|
||||
#
|
||||
# A threaded resource is a "quick and dirty" wrapper around the concept of
|
||||
# wiring up synchronous code into a standard EM::Pool. This is useful to keep
|
||||
# interfaces coherent and provide a simple approach at "making an interface
|
||||
# async-ish".
|
||||
#
|
||||
# General usage is to wrap libraries that do not support EventMachine, or to
|
||||
# have a specific number of dedicated high-cpu worker resources.
|
||||
#
|
||||
# == Basic Usage example
|
||||
#
|
||||
# This example requires the cassandra gem. The cassandra gem contains an
|
||||
# EventMachine interface, but it's sadly Fiber based and thus only works on
|
||||
# 1.9. It also requires (potentially) complex stack switching logic to reach
|
||||
# completion of nested operations. By contrast this approach provides a block
|
||||
# in which normal synchronous code can occur, but makes no attempt to wire the
|
||||
# IO into EventMachines C++ IO implementations, instead relying on the reactor
|
||||
# pattern in rb_thread_select.
|
||||
#
|
||||
# cassandra_dispatcher = ThreadedResource.new do
|
||||
# Cassandra.new('allthethings', '127.0.0.1:9160')
|
||||
# end
|
||||
#
|
||||
# pool = EM::Pool.new
|
||||
#
|
||||
# pool.add cassandra_dispatcher
|
||||
#
|
||||
# # If we don't care about the result:
|
||||
# pool.perform do |dispatcher|
|
||||
# # The following block executes inside a dedicated thread, and should not
|
||||
# # access EventMachine things:
|
||||
# dispatcher.dispatch do |cassandra|
|
||||
# cassandra.insert(:Things, '10', 'stuff' => 'things')
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # Example where we care about the result:
|
||||
# pool.perform do |dispatcher|
|
||||
# # The dispatch block is executed in the resources thread.
|
||||
# completion = dispatcher.dispatch do |cassandra|
|
||||
# cassandra.get(:Things, '10', 'stuff')
|
||||
# end
|
||||
#
|
||||
# # This block will be yielded on the EM thread:
|
||||
# completion.callback do |result|
|
||||
# EM.do_something_with(result)
|
||||
# end
|
||||
#
|
||||
# completion
|
||||
# end
|
||||
class ThreadedResource
|
||||
|
||||
# The block should return the resource that will be yielded in a dispatch.
|
||||
def initialize
|
||||
@resource = yield
|
||||
|
||||
@running = true
|
||||
@queue = ::Queue.new
|
||||
@thread = Thread.new do
|
||||
@queue.pop.call while @running
|
||||
end
|
||||
end
|
||||
|
||||
# Called on the EM thread, generally in a perform block to return a
|
||||
# completion for the work.
|
||||
def dispatch
|
||||
completion = EM::Completion.new
|
||||
@queue << lambda do
|
||||
begin
|
||||
result = yield @resource
|
||||
completion.succeed result
|
||||
rescue => e
|
||||
completion.fail e
|
||||
end
|
||||
end
|
||||
completion
|
||||
end
|
||||
|
||||
# Kill the internal thread. should only be used to cleanup - generally
|
||||
# only required for tests.
|
||||
def shutdown
|
||||
@running = false
|
||||
@queue << lambda {}
|
||||
@thread.join
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user