Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

Commit

Permalink
Add optional timeout to Promise#resolve
Browse files Browse the repository at this point in the history
Change-Id: I1ab70f070a46586554cfc90ad5c420f9f39810c1
  • Loading branch information
mpage committed May 14, 2012
1 parent e1058bb commit be2bdb9
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 8 deletions.
7 changes: 7 additions & 0 deletions lib/vcap/concurrency/errors.rb
@@ -0,0 +1,7 @@
module VCAP
module Concurrency
class Error < StandardError; end
class TimeoutError < Error; end
end
end

18 changes: 16 additions & 2 deletions lib/vcap/concurrency/promise.rb
@@ -1,5 +1,7 @@
require "thread" require "thread"


require "vcap/concurrency/errors"

module VCAP module VCAP
module Concurrency module Concurrency
end end
Expand Down Expand Up @@ -62,10 +64,22 @@ def fail(exception)
# NB: If the promise failed to be fulfilled, the error that occurred while # NB: If the promise failed to be fulfilled, the error that occurred while
# fulfilling it will be raised here. # fulfilling it will be raised here.
# #
# @param [Integer] timeout_secs If supplied, wait for no longer than this
# value before proceeding. An exception will be raised if the promise hasn't
# been fulfilled when the timeout occurs.
#
# @raise [VCAP::Concurrency::TimeoutError] Raised if the promise hasn't been
# fulfilled after +timeout_secs+ seconds since calling resolve().
#
# @return [Object] The result of the associated computation. # @return [Object] The result of the associated computation.
def resolve def resolve(timeout_secs = nil)
@lock.synchronize do @lock.synchronize do
@cond.wait(@lock) unless @done @cond.wait(@lock, timeout_secs) unless @done

if !@done
emsg = "Timed out waiting on result after #{timeout_secs}s."
raise VCAP::Concurrency::TimeoutError.new(emsg)
end


if @error if @error
raise @error raise @error
Expand Down
2 changes: 1 addition & 1 deletion lib/vcap/concurrency/version.rb
@@ -1,5 +1,5 @@
module VCAP module VCAP
module Concurrency module Concurrency
VERSION = "0.0.1" VERSION = "0.1.0"
end end
end end
21 changes: 16 additions & 5 deletions spec/promise_spec.rb
@@ -1,23 +1,22 @@
require "spec_helper" require "spec_helper"


describe VCAP::Concurrency::Promise do describe VCAP::Concurrency::Promise do
let(:promise) { VCAP::Concurrency::Promise.new }

describe "#deliver " do describe "#deliver " do
it "should deliver the supplied result to callers of resolve" do it "should deliver the supplied result to callers of resolve" do
promise = VCAP::Concurrency::Promise.new
promise.deliver(:done) promise.deliver(:done)
promise.resolve.should == :done promise.resolve.should == :done
end end


it "should raise an error if called more than once" do it "should raise an error if called more than once" do
promise = VCAP::Concurrency::Promise.new
promise.deliver promise.deliver
expect do expect do
promise.deliver promise.deliver
end.to raise_error(/completed once/) end.to raise_error(/completed once/)
end end


it "should wake up all threads that are resolving it" do it "should wake up all threads that are resolving it" do
promise = VCAP::Concurrency::Promise.new
lock = Mutex.new lock = Mutex.new
cond = ConditionVariable.new cond = ConditionVariable.new
waiting = 0 waiting = 0
Expand Down Expand Up @@ -52,7 +51,6 @@


describe "#fail" do describe "#fail" do
it "should deliver the supplied exception to callers of resolve" do it "should deliver the supplied exception to callers of resolve" do
promise = VCAP::Concurrency::Promise.new
error_text = "test error" error_text = "test error"
promise.fail(RuntimeError.new(error_text)) promise.fail(RuntimeError.new(error_text))
expect do expect do
Expand All @@ -61,12 +59,25 @@
end end


it "should raise an error if called more than once" do it "should raise an error if called more than once" do
promise = VCAP::Concurrency::Promise.new
e = RuntimeError.new("test") e = RuntimeError.new("test")
promise.fail(e) promise.fail(e)
expect do expect do
promise.fail(e) promise.fail(e)
end.to raise_error(/completed once/) end.to raise_error(/completed once/)
end end
end end

describe "#resolve" do
it "should raise an error when a timeout occurs" do
start = Time.now

expect do
promise.resolve(0.5)
end.to raise_error(VCAP::Concurrency::TimeoutError)

elapsed = Time.now - start

elapsed.should be_within(1).of(0.5)
end
end
end end

0 comments on commit be2bdb9

Please sign in to comment.