diff --git a/.gitignore b/.gitignore index d930387d..002af981 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ spec/reports test/tmp test/version_tmp tmp +.idea diff --git a/lib/makara/connection_wrapper.rb b/lib/makara/connection_wrapper.rb index e63b2eb6..c212c849 100644 --- a/lib/makara/connection_wrapper.rb +++ b/lib/makara/connection_wrapper.rb @@ -63,10 +63,10 @@ def _makara_connected? false end - def _makara_connection + def _makara_connection(force_new = false) current = @connection - if current + if current && !force_new current else # blacklisted connection or initial error new_connection = @proxy.graceful_connection_for(@config) diff --git a/lib/makara/proxy.rb b/lib/makara/proxy.rb index e3e661fb..05e9af22 100644 --- a/lib/makara/proxy.rb +++ b/lib/makara/proxy.rb @@ -24,8 +24,12 @@ def hijack_method(*method_names) method_names.each do |method_name| define_method method_name do |*args, &block| - appropriate_connection(method_name, args) do |con| - con.send(method_name, *args, &block) + + makara_config = @config.with_indifferent_access[:makara] + if makara_config.key?(:retry_exceptions) && (retry_exceptions = makara_config[:retry_exceptions]).present? + _execute_with_connection_and_retry_exceptions(retry_exceptions, args, block, method_name) + else + _execute_with_connection(args, block, method_name) end end end @@ -162,6 +166,40 @@ def any_connection end end + MAX_RETRY_COUNT = 10 + + def _execute_with_connection_and_retry_exceptions(retry_exceptions, args, block, method_name) + begin + should_retry = false + + appropriate_connection(method_name, args) do |con| + con.send(method_name, *args, &block) + end + + rescue Exception => actual_exception + retry_attempts = retry_exceptions.inject({}) { |memo, retry_exception| memo[retry_exception['name']] = 0; memo } + retry_exceptions.each do |retry_exception| + if actual_exception.class.to_s == retry_exception['name'] + sleep retry_exception['time_between_retries_in_seconds'] || 0.1 + retry_attempt = (retry_attempts[actual_exception.class.to_s] += 1) + + max_attempts = retry_exception['retry_count'] || MAX_RETRY_COUNT + if retry_attempt < max_attempts && retry_attempt < MAX_RETRY_COUNT + should_retry = true + end + end + end + retry if should_retry + raise actual_exception + end + end + + def _execute_with_connection(args, block, method_name) + appropriate_connection(method_name, args) do |con| + con.send(method_name, *args, &block) + end + end + # based on the method_name and args, provide the appropriate connection # mark this proxy as hijacked so the underlying connection does not attempt to check # with back with this proxy.