Skip to content

Instantly share code, notes, and snippets.

@tisba
Created July 6, 2010 09:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tisba/465200 to your computer and use it in GitHub Desktop.
Save tisba/465200 to your computer and use it in GitHub Desktop.
diff --git a/riak-client/lib/riak/client.rb b/riak-client/lib/riak/client.rb
index 127c2c8..be94f75 100644
--- a/riak-client/lib/riak/client.rb
+++ b/riak-client/lib/riak/client.rb
@@ -35,6 +35,9 @@ module Riak
# @return [Fixnum] The port of the Riak HTTP endpoint
attr_reader :port
+ # @return [Array] of Riak HTTP endpoint hashes each consisting of :host and :port
+ attr_accessor :backends
+
# @return [String] The internal client ID used by Riak to route responses
attr_reader :client_id
@@ -60,6 +63,24 @@ module Riak
self.prefix = options[:prefix] || "/riak/"
self.mapred = options[:mapred] || "/mapred"
raise ArgumentError, t("missing_host_and_port") unless @host && @port
+
+ self.backends = [{:host => self.host, :port => self.port}]
+ end
+
+ # Add a backend to the pool
+ # @param [String] the host (IP or hostname) of the riak node to be added
+ # @param [Fixnum] the port of the riak node to be added
+ def add_backend(host, port)
+ self.backends << {:host => host, :port => port}
+ end
+
+ # Switches through the backends by settinh the next one and appending the current to the end of the pool
+ # @return [Hash] the new backend (may be the same, if self.backends only contains one element)
+ def next_backend
+ self.backends << self.backends.shift
+ self.host = self.backends[0][:host]
+ self.port = self.backends[0][:port]
+ self.backends[0]
end
# Set the client ID for this client. Must be a string or Fixnum value 0 =< value < MAX_CLIENT_ID.
diff --git a/riak-client/lib/riak/client/http_backend.rb b/riak-client/lib/riak/client/http_backend.rb
index 072c4f7..ff63f3f 100644
--- a/riak-client/lib/riak/client/http_backend.rb
+++ b/riak-client/lib/riak/client/http_backend.rb
@@ -68,7 +68,9 @@ module Riak
def get(expect, *resource, &block)
headers = default_headers.merge(resource.extract_options!)
verify_path!(resource)
- perform(:get, path(*resource), headers, expect, &block)
+ retry_and_switch_backend_if_needed do
+ perform(:get, path(*resource), headers, expect, &block)
+ end
end
# Performs a PUT request to the specified resource on the Riak server.
@@ -89,7 +91,9 @@ module Riak
def put(expect, *resource, &block)
headers = default_headers.merge(resource.extract_options!)
uri, data = verify_path_and_body!(resource)
- perform(:put, path(*uri), headers, expect, data, &block)
+ retry_and_switch_backend_if_needed do
+ perform(:put, path(*uri), headers, expect, data, &block)
+ end
end
# Performs a POST request to the specified resource on the Riak server.
@@ -110,7 +114,9 @@ module Riak
def post(expect, *resource, &block)
headers = default_headers.merge(resource.extract_options!)
uri, data = verify_path_and_body!(resource)
- perform(:post, path(*uri), headers, expect, data, &block)
+ retry_and_switch_backend_if_needed do
+ perform(:post, path(*uri), headers, expect, data, &block)
+ end
end
# Performs a DELETE request to the specified resource on the Riak server.
@@ -130,7 +136,9 @@ module Riak
def delete(expect, *resource, &block)
headers = default_headers.merge(resource.extract_options!)
verify_path!(resource)
- perform(:delete, path(*resource), headers, expect, &block)
+ retry_and_switch_backend_if_needed do
+ perform(:delete, path(*resource), headers, expect, &block)
+ end
end
# @return [URI] The calculated root URI for the Riak HTTP endpoint
@@ -170,7 +178,7 @@ module Riak
resource = Array(resource).flatten
raise ArgumentError, t("resource_path_short") unless resource.length > 1 || resource.include?(@client.mapred)
end
-
+
# Checks the expected response codes against the actual response code. Use internally when
# implementing {#perform}.
# @param [String, Fixnum, Array<String,Fixnum>] expected the expected response code(s)
@@ -189,7 +197,7 @@ module Riak
def return_body?(method, code, has_block)
method != :head && !valid_response?([204,205,304], code) && !has_block
end
-
+
# Executes requests according to the underlying HTTP client library semantics.
# @abstract Subclasses must implement this internal method to perform HTTP requests
# according to the API of their HTTP libraries.
@@ -204,6 +212,23 @@ module Riak
def perform(method, uri, headers, expect, body=nil)
raise NotImplementedError
end
+
+ private
+
+ # Meant to be used internally for the get, put, post and delete methods
+ # to keep them DRY and catch errors from the (actual) HTTP backend
+ # implementation, switch the backend and retry again. FailedRequest
+ # Exceptions are raised again
+ def retry_and_switch_backend_if_needed
+ begin
+ yield
+ rescue Exception => e
+ raise e if e.class == FailedRequest
+ warn t("backend_not_working", :uri => root_uri.to_s, :exception => e.to_s)
+ client.next_backend
+ retry
+ end
+ end
end
end
end
diff --git a/riak-client/lib/riak/locale/en.yml b/riak-client/lib/riak/locale/en.yml
index 9a217fb..4c95291 100644
--- a/riak-client/lib/riak/locale/en.yml
+++ b/riak-client/lib/riak/locale/en.yml
@@ -35,3 +35,4 @@ en:
too_few_arguments: "too few arguments: %{params}"
walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
+ backend_not_working: "backend %{uri} is not working properly: %{exception}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment