|
|
|
@ -38,6 +38,103 @@ $grpc_signals = [] |
|
|
|
|
|
|
|
|
|
# GRPC contains the General RPC module. |
|
|
|
|
module GRPC |
|
|
|
|
# Pool is a simple thread pool. |
|
|
|
|
class Pool |
|
|
|
|
# Default keep alive period is 1s |
|
|
|
|
DEFAULT_KEEP_ALIVE = 1 |
|
|
|
|
|
|
|
|
|
def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE) |
|
|
|
|
fail 'pool size must be positive' unless size > 0 |
|
|
|
|
@jobs = Queue.new |
|
|
|
|
@size = size |
|
|
|
|
@stopped = false |
|
|
|
|
@stop_mutex = Mutex.new |
|
|
|
|
@stop_cond = ConditionVariable.new |
|
|
|
|
@workers = [] |
|
|
|
|
@keep_alive = keep_alive |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Returns the number of jobs waiting |
|
|
|
|
def jobs_waiting |
|
|
|
|
@jobs.size |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Runs the given block on the queue with the provided args. |
|
|
|
|
# |
|
|
|
|
# @param args the args passed blk when it is called |
|
|
|
|
# @param blk the block to call |
|
|
|
|
def schedule(*args, &blk) |
|
|
|
|
fail 'already stopped' if @stopped |
|
|
|
|
return if blk.nil? |
|
|
|
|
logger.info('schedule another job') |
|
|
|
|
@jobs << [blk, args] |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Starts running the jobs in the thread pool. |
|
|
|
|
def start |
|
|
|
|
fail 'already stopped' if @stopped |
|
|
|
|
until @workers.size == @size.to_i |
|
|
|
|
next_thread = Thread.new do |
|
|
|
|
catch(:exit) do # allows { throw :exit } to kill a thread |
|
|
|
|
loop_execute_jobs |
|
|
|
|
end |
|
|
|
|
remove_current_thread |
|
|
|
|
end |
|
|
|
|
@workers << next_thread |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Stops the jobs in the pool |
|
|
|
|
def stop |
|
|
|
|
logger.info('stopping, will wait for all the workers to exit') |
|
|
|
|
@workers.size.times { schedule { throw :exit } } |
|
|
|
|
@stopped = true |
|
|
|
|
@stop_mutex.synchronize do # wait @keep_alive for works to stop |
|
|
|
|
@stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0 |
|
|
|
|
end |
|
|
|
|
forcibly_stop_workers |
|
|
|
|
logger.info('stopped, all workers are shutdown') |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
protected |
|
|
|
|
|
|
|
|
|
# Forcibly shutdown any threads that are still alive. |
|
|
|
|
def forcibly_stop_workers |
|
|
|
|
return unless @workers.size > 0 |
|
|
|
|
logger.info("forcibly terminating #{@workers.size} worker(s)") |
|
|
|
|
@workers.each do |t| |
|
|
|
|
next unless t.alive? |
|
|
|
|
begin |
|
|
|
|
t.exit |
|
|
|
|
rescue StandardError => e |
|
|
|
|
logger.warn('error while terminating a worker') |
|
|
|
|
logger.warn(e) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# removes the threads from workers, and signal when all the |
|
|
|
|
# threads are complete. |
|
|
|
|
def remove_current_thread |
|
|
|
|
@stop_mutex.synchronize do |
|
|
|
|
@workers.delete(Thread.current) |
|
|
|
|
@stop_cond.signal if @workers.size == 0 |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def loop_execute_jobs |
|
|
|
|
loop do |
|
|
|
|
begin |
|
|
|
|
blk, args = @jobs.pop |
|
|
|
|
blk.call(*args) |
|
|
|
|
rescue StandardError => e |
|
|
|
|
logger.warn('Error in worker thread') |
|
|
|
|
logger.warn(e) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# RpcServer hosts a number of services and makes them available on the |
|
|
|
|
# network. |
|
|
|
|
class RpcServer |
|
|
|
@ -320,93 +417,6 @@ module GRPC |
|
|
|
|
an_rpc.deadline) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Pool is a simple thread pool for running server requests. |
|
|
|
|
class Pool |
|
|
|
|
# Default keep alive period is 1s |
|
|
|
|
DEFAULT_KEEP_ALIVE = 1 |
|
|
|
|
|
|
|
|
|
def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE) |
|
|
|
|
fail 'pool size must be positive' unless size > 0 |
|
|
|
|
@jobs = Queue.new |
|
|
|
|
@size = size |
|
|
|
|
@stopped = false |
|
|
|
|
@stop_mutex = Mutex.new |
|
|
|
|
@stop_cond = ConditionVariable.new |
|
|
|
|
@workers = [] |
|
|
|
|
@keep_alive = keep_alive |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Returns the number of jobs waiting |
|
|
|
|
def jobs_waiting |
|
|
|
|
@jobs.size |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Runs the given block on the queue with the provided args. |
|
|
|
|
# |
|
|
|
|
# @param args the args passed blk when it is called |
|
|
|
|
# @param blk the block to call |
|
|
|
|
def schedule(*args, &blk) |
|
|
|
|
fail 'already stopped' if @stopped |
|
|
|
|
return if blk.nil? |
|
|
|
|
logger.info('schedule another job') |
|
|
|
|
@jobs << [blk, args] |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Starts running the jobs in the thread pool. |
|
|
|
|
def start |
|
|
|
|
fail 'already stopped' if @stopped |
|
|
|
|
until @workers.size == @size.to_i |
|
|
|
|
next_thread = Thread.new do |
|
|
|
|
catch(:exit) do # allows { throw :exit } to kill a thread |
|
|
|
|
loop do |
|
|
|
|
begin |
|
|
|
|
blk, args = @jobs.pop |
|
|
|
|
blk.call(*args) |
|
|
|
|
rescue StandardError => e |
|
|
|
|
logger.warn('Error in worker thread') |
|
|
|
|
logger.warn(e) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# removes the threads from workers, and signal when all the |
|
|
|
|
# threads are complete. |
|
|
|
|
@stop_mutex.synchronize do |
|
|
|
|
@workers.delete(Thread.current) |
|
|
|
|
@stop_cond.signal if @workers.size == 0 |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
@workers << next_thread |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Stops the jobs in the pool |
|
|
|
|
def stop |
|
|
|
|
logger.info('stopping, will wait for all the workers to exit') |
|
|
|
|
@workers.size.times { schedule { throw :exit } } |
|
|
|
|
@stopped = true |
|
|
|
|
|
|
|
|
|
@stop_mutex.synchronize do |
|
|
|
|
@stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0 |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Forcibly shutdown any threads that are still alive. |
|
|
|
|
if @workers.size > 0 |
|
|
|
|
logger.info("forcibly terminating #{@workers.size} worker(s)") |
|
|
|
|
@workers.each do |t| |
|
|
|
|
next unless t.alive? |
|
|
|
|
begin |
|
|
|
|
t.exit |
|
|
|
|
rescue StandardError => e |
|
|
|
|
logger.warn('error while terminating a worker') |
|
|
|
|
logger.warn(e) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
logger.info('stopped, all workers are shutdown') |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
protected |
|
|
|
|
|
|
|
|
|
def rpc_descs |
|
|
|
|