Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 11 commits
  • 10 files changed
  • 0 commit comments
  • 2 contributors
View
8 History.txt
@@ -1,3 +1,11 @@
+= 0.4.2 / 2009-11-27
+ * Major changes
+ * Switch to using raw socket timeouts over buffered io (Linux only)
+
+= 0.4.1 / 2009-11-26
+ * Major changes
+ * Backport timeout option
+
= 0.4.0 / 2009-10-08
* Major changes
* Convert to use BERT gem.
View
12 README.md
@@ -56,6 +56,18 @@ The underlying BERT-RPC transaction of the above cast is:
<- {noreply}
+Documentation
+-------------
+
+Creating a service:
+
+ # No timeout
+ svc = BERTRPC::Service.new('localhost', 9999)
+
+ # 10s socket read timeout, raises BERTRPC::ReadTimeoutError
+ svc = BERTRPC::Service.new('localhost', 9999, 10)
+
+
Copyright
---------
View
2  VERSION
@@ -1 +1 @@
-0.4.0
+0.4.2
View
9 bertrpc.gemspec
@@ -1,15 +1,15 @@
# Generated by jeweler
-# DO NOT EDIT THIS FILE
-# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{bertrpc}
- s.version = "0.4.0"
+ s.version = "0.4.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Tom Preston-Werner"]
- s.date = %q{2009-10-08}
+ s.date = %q{2009-11-27}
s.email = %q{tom@mojombo.com}
s.extra_rdoc_files = [
"LICENSE",
@@ -70,3 +70,4 @@ Gem::Specification.new do |s|
s.add_dependency(%q<erlectricity>, [">= 1.0.1"])
end
end
+
View
3  lib/bertrpc.rb
@@ -1,9 +1,10 @@
require 'bert'
require 'socket'
+require 'net/protocol'
require 'bertrpc/service'
require 'bertrpc/request'
require 'bertrpc/mod'
require 'bertrpc/encodes'
require 'bertrpc/action'
-require 'bertrpc/errors'
+require 'bertrpc/errors'
View
29 lib/bertrpc/action.rb
@@ -24,7 +24,7 @@ def write(sock, bert)
end
def transaction(bert_request)
- sock = TCPSocket.new(@svc.host, @svc.port)
+ sock = connect_to(@svc.host, @svc.port, @svc.timeout)
if @req.options
if @req.options[:cache] && @req.options[:cache][0] == :validation
@@ -44,6 +44,31 @@ def transaction(bert_request)
bert_response
rescue Errno::ECONNREFUSED
raise ConnectionError.new("Unable to connect to #{@svc.host}:#{@svc.port}")
+ rescue Errno::EAGAIN
+ raise ReadTimeoutError.new(@svc.host, @svc.port, @svc.timeout)
+ end
+
+ # Creates a socket object which does speedy, non-blocking reads
+ # and can perform reliable read timeouts.
+ #
+ # Raises Timeout::Error on timeout.
+ #
+ # +host+ String address of the target TCP server
+ # +port+ Integer port of the target TCP server
+ # +timeout+ Optional Integer (in seconds) of the read timeout
+ def connect_to(host, port, timeout = nil)
+ sock = TCPSocket.new(host, port)
+ sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
+
+ if timeout
+ secs = Integer(timeout)
+ usecs = Integer((timeout - secs) * 1_000_000)
+ optval = [secs, usecs].pack("l_2")
+ sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
+ sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
+ end
+
+ sock
end
end
-end
+end
View
12 lib/bertrpc/errors.rb
@@ -28,6 +28,16 @@ class ConnectionError < BERTRPCError
end
+ # Raised when we don't get a response from a server in a timely
+ # manner. This typically occurs in spite of a successful connection.
+ class ReadTimeoutError < BERTRPCError
+ attr_reader :host, :port, :timeout
+ def initialize(host, port, timeout)
+ @host, @port, @timeout = host, port, timeout
+ super("No response from #{host}:#{port} in #{timeout}s")
+ end
+ end
+
class ProtocolError < BERTRPCError
NO_HEADER = [0, "Unable to read length header from server."]
NO_DATA = [1, "Unable to read data from server."]
@@ -48,4 +58,4 @@ class ProxyError < BERTRPCError
class InvalidOption < BERTRPCError
end
-end
+end
View
7 lib/bertrpc/service.rb
@@ -1,10 +1,11 @@
module BERTRPC
class Service
- attr_accessor :host, :port
+ attr_accessor :host, :port, :timeout
- def initialize(host, port)
+ def initialize(host, port, timeout = nil)
@host = host
@port = port
+ @timeout = timeout
end
def call(options = nil)
@@ -31,4 +32,4 @@ def verify_options(options)
end
end
end
-end
+end
View
28 test/action_test.rb
@@ -49,7 +49,7 @@ class ActionTest < Test::Unit::TestCase
@req = @svc.call
@call = BERTRPC::Action.new(@svc, @req, :mymod, :myfun, [])
end
-
+
should "read and write BERT-Ps from the socket" do
io = stub()
io.expects(:write).with("\000\000\000\003")
@@ -57,7 +57,7 @@ class ActionTest < Test::Unit::TestCase
io.expects(:read).with(4).returns("\000\000\000\003")
io.expects(:read).with(3).returns("bar")
io.expects(:close)
- TCPSocket.expects(:new).returns(io)
+ @call.expects(:connect_to).returns(io)
assert_equal "bar", @call.transaction("foo")
end
@@ -66,7 +66,7 @@ class ActionTest < Test::Unit::TestCase
io.expects(:write).with("\000\000\000\003")
io.expects(:write).with("foo")
io.expects(:read).with(4).returns(nil)
- TCPSocket.expects(:new).returns(io)
+ @call.expects(:connect_to).returns(io)
begin
@call.transaction("foo")
fail "Should have thrown an error"
@@ -74,14 +74,14 @@ class ActionTest < Test::Unit::TestCase
assert_equal 0, e.code
end
end
-
+
should "raise a ProtocolError when the data is invalid" do
io = stub()
io.expects(:write).with("\000\000\000\003")
io.expects(:write).with("foo")
io.expects(:read).with(4).returns("\000\000\000\003")
io.expects(:read).with(3).returns(nil)
- TCPSocket.expects(:new).returns(io)
+ @call.expects(:connect_to).returns(io)
begin
@call.transaction("foo")
fail "Should have thrown an error"
@@ -89,6 +89,22 @@ class ActionTest < Test::Unit::TestCase
assert_equal 1, e.code
end
end
+
+ should "raise a ReadTimeoutError when the connection times out" do
+ io = stub()
+ io.expects(:write).with("\000\000\000\003")
+ io.expects(:write).with("foo")
+ io.expects(:read).with(4).raises(Errno::EAGAIN)
+ @call.expects(:connect_to).returns(io)
+ begin
+ @call.transaction("foo")
+ fail "Should have thrown an error"
+ rescue BERTRPC::ReadTimeoutError => e
+ assert_equal 0, e.code
+ assert_equal 'localhost', e.host
+ assert_equal 9941, e.port
+ end
+ end
end
end
-end
+end
View
7 test/service_test.rb
@@ -2,10 +2,15 @@
class ServiceTest < Test::Unit::TestCase
context "A Service" do
- should "be created with host and port" do
+ should "be creatable with host and port" do
svc = BERTRPC::Service.new('localhost', 9941)
assert svc.is_a?(BERTRPC::Service)
end
+
+ should "be creatable with host, port, and timeout" do
+ svc = BERTRPC::Service.new('localhost', 9941, 5)
+ assert svc.is_a?(BERTRPC::Service)
+ end
end
context "A Service Instance's" do

No commit comments for this range

Something went wrong with that request. Please try again.