Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to configure httpclient send/receive timeout #163

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 38 additions & 34 deletions lib/neography/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,57 @@ class Config
:max_threads,
:authentication, :username, :password,
:parser, :max_execution_time,
:proxy
:proxy, :http_send_timeout, :http_receive_timeout

def initialize
set_defaults
end

def to_hash
{
:protocol => @protocol,
:server => @server,
:port => @port,
:directory => @directory,
:cypher_path => @cypher_path,
:gremlin_path => @gremlin_path,
:log_file => @log_file,
:log_enabled => @log_enabled,
:logger => @logger,
:slow_log_threshold => @slow_log_threshold,
:max_threads => @max_threads,
:authentication => @authentication,
:username => @username,
:password => @password,
:parser => @parser,
:max_execution_time => @max_execution_time,
:proxy => @proxy
:protocol => @protocol,
:server => @server,
:port => @port,
:directory => @directory,
:cypher_path => @cypher_path,
:gremlin_path => @gremlin_path,
:log_file => @log_file,
:log_enabled => @log_enabled,
:logger => @logger,
:slow_log_threshold => @slow_log_threshold,
:max_threads => @max_threads,
:authentication => @authentication,
:username => @username,
:password => @password,
:parser => @parser,
:max_execution_time => @max_execution_time,
:proxy => @proxy,
:http_send_timeout => @http_send_timeout,
:http_receive_timeout => @http_receive_timeout
}
end

private

def set_defaults
@protocol = "http://"
@server = "localhost"
@port = 7474
@directory = ""
@cypher_path = "/cypher"
@gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
@log_file = "neography.log"
@log_enabled = false
@slow_log_threshold = 0
@max_threads = 20
@authentication = nil
@username = nil
@password = nil
@parser = MultiJsonParser
@max_execution_time = 6000
@proxy = nil
@protocol = "http://"
@server = "localhost"
@port = 7474
@directory = ""
@cypher_path = "/cypher"
@gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
@log_file = "neography.log"
@log_enabled = false
@slow_log_threshold = 0
@max_threads = 20
@authentication = nil
@username = nil
@password = nil
@parser = MultiJsonParser
@max_execution_time = 6000
@proxy = nil
@http_send_timeout = 1200
@http_receive_timeout = 1200
end

end
Expand Down
34 changes: 17 additions & 17 deletions lib/neography/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ module WasCreated
class Connection
USER_AGENT = "Neography/#{Neography::VERSION}"
ACTIONS = ["get", "post", "put", "delete"]

attr_accessor :protocol, :server, :port, :directory,
:cypher_path, :gremlin_path,
:log_file, :log_enabled, :logger, :slow_log_threshold,
:max_threads,
:authentication, :username, :password,
:parser, :client,
:proxy
:proxy, :http_send_timeout, :http_receive_timeout

def initialize(options = ENV['NEO4J_URL'] || {})
config = merge_configuration(options)
save_local_configuration(config)
@client ||= HTTPClient.new(config[:proxy])
@client.send_timeout = 1200 # 10 minutes
@client.receive_timeout = 1200
@client.send_timeout = config[:http_send_timeout]
@client.receive_timeout = config[:http_receive_timeout]
authenticate
end

Expand All @@ -42,16 +42,16 @@ def merge_options(options)
end

ACTIONS.each do |action|
define_method(action) do |path, options = {}|
define_method(action) do |path, options = {}|
# This ugly hack is required because internal Batch paths do not start with "/db/data"
# if somebody has a cleaner solution... pull request please!
path = "/db/data" + path if ["node", "relationship", "transaction", "cypher", "propertykeys", "schema", "label", "labels", "batch", "index", "ext"].include?(path.split("/")[1].split("?").first)
query_path = configuration + path
query_body = merge_options(options)[:body]
query_body = merge_options(options)[:body]
log path, query_body do
evaluate_response(@client.send(action.to_sym, query_path, query_body, merge_options(options)[:headers]), path, query_body)
evaluate_response(@client.send(action.to_sym, query_path, query_body, merge_options(options)[:headers]), path, query_body)
end
end
end
end

def log(path, body)
Expand Down Expand Up @@ -80,7 +80,7 @@ def authenticate(path = nil)
@client.www_auth.basic_auth.challenge(configuration) if auth_type == 'basic_auth'
end
end

private

def merge_configuration(options)
Expand Down Expand Up @@ -143,13 +143,13 @@ def handle_batch(response)
body = @parser.json(response.body.force_encoding("UTF-8"))
body.each do |result|
if result["status"] >= 400
code = result["status"]
code = result["status"]
break
end
end
return code, body, true
end

def return_result(response, code, body, parsed, path, query_body)
case code
when 200
Expand All @@ -166,7 +166,7 @@ def return_result(response, code, body, parsed, path, query_body)
when 400..500
handle_4xx_500_response(response, code, body, path, query_body)
nil
end
end
end

def handle_4xx_500_response(response, code, body, path, query_body)
Expand All @@ -184,7 +184,7 @@ def handle_4xx_500_response(response, code, body, path, query_body)
parsed_body = result["body"] || result
break
end
end
end
else
parsed_body = @parser.json(body)
end
Expand All @@ -195,7 +195,7 @@ def handle_4xx_500_response(response, code, body, path, query_body)
@logger.error "#{response.dump} error: #{body}" if @log_enabled
raise_errors(code, parsed_body["exception"], message, stacktrace, request, index)
end

def raise_errors(code, exception, message, stacktrace, request, index)
error = nil
case code
Expand All @@ -215,12 +215,12 @@ def raise_errors(code, exception, message, stacktrace, request, index)
when /RelationshipNotFoundException/ ; RelationshipNotFoundException
when /NotFoundException/ ; NotFoundException
when /UniquePathNotUniqueException/ ; UniquePathNotUniqueException
when /DeadlockDetectedException/ ; DeadlockDetectedException
when /DeadlockDetectedException/ ; DeadlockDetectedException
else
NeographyError
end
raise error.new(message, code, stacktrace, request, index)

raise error.new(message, code, stacktrace, request, index)
end

def parse_string_options(options)
Expand Down
73 changes: 39 additions & 34 deletions spec/unit/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,49 @@ module Neography

context "defaults" do

its(:protocol) { should == 'http://' }
its(:server) { should == 'localhost' }
its(:port) { should == 7474 }
its(:directory) { should == '' }
its(:cypher_path) { should == '/cypher' }
its(:gremlin_path) { should == '/ext/GremlinPlugin/graphdb/execute_script' }
its(:log_file) { should == 'neography.log' }
its(:log_enabled) { should == false }
its(:logger) { should == nil }
its(:slow_log_threshold) { should == 0 }
its(:max_threads) { should == 20 }
its(:authentication) { should == nil }
its(:username) { should == nil }
its(:password) { should == nil }
its(:parser) { should == MultiJsonParser}
its(:max_execution_time) { should == 6000 }
its(:proxy) { should == nil }
its(:protocol) { should == 'http://' }
its(:server) { should == 'localhost' }
its(:port) { should == 7474 }
its(:directory) { should == '' }
its(:cypher_path) { should == '/cypher' }
its(:gremlin_path) { should == '/ext/GremlinPlugin/graphdb/execute_script' }
its(:log_file) { should == 'neography.log' }
its(:log_enabled) { should == false }
its(:logger) { should == nil }
its(:slow_log_threshold) { should == 0 }
its(:max_threads) { should == 20 }
its(:authentication) { should == nil }
its(:username) { should == nil }
its(:password) { should == nil }
its(:parser) { should == MultiJsonParser}
its(:max_execution_time) { should == 6000 }
its(:proxy) { should == nil }
its(:http_send_timeout) { should == 1200 }
its(:http_receive_timeout) { should == 1200 }


it "has a hash representation" do
expected_hash = {
:protocol => 'http://',
:server => 'localhost',
:port => 7474,
:directory => '',
:cypher_path => '/cypher',
:gremlin_path => '/ext/GremlinPlugin/graphdb/execute_script',
:log_file => 'neography.log',
:log_enabled => false,
:logger => nil,
:slow_log_threshold => 0,
:max_threads => 20,
:authentication => nil,
:username => nil,
:password => nil,
:parser => MultiJsonParser,
:max_execution_time => 6000,
:proxy => nil
:protocol => 'http://',
:server => 'localhost',
:port => 7474,
:directory => '',
:cypher_path => '/cypher',
:gremlin_path => '/ext/GremlinPlugin/graphdb/execute_script',
:log_file => 'neography.log',
:log_enabled => false,
:logger => nil,
:slow_log_threshold => 0,
:max_threads => 20,
:authentication => nil,
:username => nil,
:password => nil,
:parser => MultiJsonParser,
:max_execution_time => 6000,
:proxy => nil,
:http_send_timeout => 1200,
:http_receive_timeout => 1200

}
config.to_hash.should == expected_hash
end
Expand Down
21 changes: 20 additions & 1 deletion spec/unit/connection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,27 @@ module Neography
}
}
end

context "httpclient" do
let(:httpclient) { double(:http_client) }
let(:options) do
{
:http_send_timeout => 120,
:http_receive_timeout => 120
}
end

it 'configures send/receive timeout' do
HTTPClient.should_receive(:new).and_return(httpclient)
httpclient.should_receive(:send_timeout=).with(120)
httpclient.should_receive(:receive_timeout=).with(120)
connection
end
end
end



context "string option" do
let(:options) { "https://user:pass@somehost:8585/path" }

Expand Down Expand Up @@ -256,4 +275,4 @@ module Neography
end
end

class Foo; end
class Foo; end