Permalink
Browse files

Add optional timeout to Promise#resolve

Change-Id: I1ab70f070a46586554cfc90ad5c420f9f39810c1
  • Loading branch information...
1 parent e1058bb commit be2bdb9f64a066f268d7537223ee24ae18e03cf7 mpage committed May 14, 2012
Showing with 40 additions and 8 deletions.
  1. +7 −0 lib/vcap/concurrency/errors.rb
  2. +16 −2 lib/vcap/concurrency/promise.rb
  3. +1 −1 lib/vcap/concurrency/version.rb
  4. +16 −5 spec/promise_spec.rb
@@ -0,0 +1,7 @@
+module VCAP
+ module Concurrency
+ class Error < StandardError; end
+ class TimeoutError < Error; end
+ end
+end
+
@@ -1,5 +1,7 @@
require "thread"
+require "vcap/concurrency/errors"
+
module VCAP
module Concurrency
end
@@ -62,10 +64,22 @@ def fail(exception)
# NB: If the promise failed to be fulfilled, the error that occurred while
# 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.
- def resolve
+ def resolve(timeout_secs = nil)
@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
raise @error
@@ -1,5 +1,5 @@
module VCAP
module Concurrency
- VERSION = "0.0.1"
+ VERSION = "0.1.0"
end
end
View
@@ -1,23 +1,22 @@
require "spec_helper"
describe VCAP::Concurrency::Promise do
+ let(:promise) { VCAP::Concurrency::Promise.new }
+
describe "#deliver " do
it "should deliver the supplied result to callers of resolve" do
- promise = VCAP::Concurrency::Promise.new
promise.deliver(:done)
promise.resolve.should == :done
end
it "should raise an error if called more than once" do
- promise = VCAP::Concurrency::Promise.new
promise.deliver
expect do
promise.deliver
end.to raise_error(/completed once/)
end
it "should wake up all threads that are resolving it" do
- promise = VCAP::Concurrency::Promise.new
lock = Mutex.new
cond = ConditionVariable.new
waiting = 0
@@ -52,7 +51,6 @@
describe "#fail" do
it "should deliver the supplied exception to callers of resolve" do
- promise = VCAP::Concurrency::Promise.new
error_text = "test error"
promise.fail(RuntimeError.new(error_text))
expect do
@@ -61,12 +59,25 @@
end
it "should raise an error if called more than once" do
- promise = VCAP::Concurrency::Promise.new
e = RuntimeError.new("test")
promise.fail(e)
expect do
promise.fail(e)
end.to raise_error(/completed once/)
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

0 comments on commit be2bdb9

Please sign in to comment.