Skip to content

Commit

Permalink
should still timeout for task never processed in thread pool
Browse files Browse the repository at this point in the history
  • Loading branch information
godfat committed Jan 10, 2015
1 parent 147661d commit 07ad72b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 15 deletions.
15 changes: 10 additions & 5 deletions lib/rest-core/promise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,14 @@ def defer
else
backtrace = caller + self.class.backtrace # retain the backtrace so far
if pool_size > 0
self.task = client_class.thread_pool.defer(mutex) do
Thread.current[:backtrace] = backtrace
protected_yield{ yield }
Thread.current[:backtrace] = nil
mutex.synchronize do
# still timing it out if the task never processed
env[TIMER].on_timeout{ cancel_task } if env[TIMER]
self.task = client_class.thread_pool.defer(mutex) do
Thread.current[:backtrace] = backtrace
protected_yield{ yield }
Thread.current[:backtrace] = nil
end
end
else
self.thread = Thread.new do
Expand Down Expand Up @@ -171,7 +175,8 @@ def protected_yield
end

def timeout_protected_yield
env[TIMER].on_timeout{ cancel_task } # set timeout
# timeout might already be set for thread_pool (pool_size > 0)
env[TIMER].on_timeout{ cancel_task } unless env[TIMER].block
yield
ensure
env[TIMER].cancel
Expand Down
10 changes: 4 additions & 6 deletions lib/rest-core/thread_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,10 @@ def idle_time
end

def defer mutex=nil, &job
mutex.synchronize do
task = Task.new(job, mutex)
queue << task
spawn_worker if waiting == 0 && workers.size < max_size
task
end
task = Task.new(job, mutex)
queue << task
spawn_worker if waiting == 0 && workers.size < max_size
task
end

def trim force=false
Expand Down
33 changes: 29 additions & 4 deletions test/test_timeout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,36 +28,61 @@
lambda{ sleep 0.01 }.should.not.raise(Timeout::Error)
end

would 'cancel the task if timing out' do
timer = Object.new.instance_eval do
def on_timeout; yield ; end
def fake_timer
Object.new.instance_eval do
@block = nil
def on_timeout; @block = true; Thread.new{yield}; end
def error ; 'boom'; end
def cancel ; ; end
def block ; @block; end
self
end
app = RC::Builder.client do
end

def sleeping_app
RC::Builder.client do
run Class.new(RC::Engine){
def request _, _
sleep
end
}
end
end

would 'cancel the task if timing out for thread pool' do
timer = fake_timer
app = sleeping_app
app.pool_size = 1
app.new.request(RC::TIMER => timer, RC::ASYNC => true).
message.should.eq 'boom'
timer.block.should.not.nil?
end

would 'still timeout if the task never processed for thread pool' do
app = sleeping_app
app.pool_size = 1
app.new.request(RC::TIMER => fake_timer, RC::ASYNC => true) do |e|
e.message.should.eq 'boom'
app.new.request(RC::TIMER => fake_timer, RC::ASYNC => true).tap{}
end
app.wait
end

would 'interrupt the task if timing out' do
rd, wr = IO.pipe
timer = Object.new.instance_eval do
@block = nil
define_singleton_method :on_timeout do |&block|
@block = block
Thread.new do
rd.gets
block.call
@block = nil
end
end
def error ; 'boom'; end
def cancel ; ; end
def block ; @block; end
self
end
app = RC::Builder.client do
Expand Down

0 comments on commit 07ad72b

Please sign in to comment.