rf-web/vendor/bundle/gems/eventmachine-1.2.7/lib/em/threaded_resource.rb
2019-10-21 10:18:17 +02:00

91 lines
2.8 KiB
Ruby

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