neo4j-ruby-driver 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ffi/bolt/config.rb +26 -1
- data/ffi/bolt/socket_options.rb +14 -0
- data/ffi/neo4j/driver.rb +2 -0
- data/ffi/neo4j/driver/config.rb +1 -1
- data/ffi/neo4j/driver/graph_database.rb +2 -2
- data/ffi/neo4j/driver/internal/async/direct_connection.rb +2 -1
- data/ffi/neo4j/driver/internal/direct_connection_provider.rb +3 -2
- data/ffi/neo4j/driver/internal/driver_factory.rb +27 -8
- data/ffi/neo4j/driver/internal/error_handling.rb +22 -0
- data/ffi/neo4j/driver/internal/handlers/pull_all_response_handler.rb +0 -2
- data/ffi/neo4j/driver/internal/handlers/response_handler.rb +3 -1
- data/ffi/neo4j/driver/internal/network_session.rb +1 -6
- data/ffi/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +80 -0
- data/lib/neo4j/driver/version.rb +1 -1
- metadata +4 -3
- data/ffi/bolt/values_private.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c7d38011d191d0e26b26b02e6b147672b27806cd66d9ebb416d326bc8ed0406
|
4
|
+
data.tar.gz: 8bef825331172211356c41ba82a7b5d5c927f939d6e0a716fb6a7f0a18cfb947
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ceec98de33377a4dea166d894ba5c6179ff7510744c6efbaa07fbb5dfbd237c0b08278587f9ebf410f601a41e006d395cbcc3f0ebd9114439348bc24bab25d3
|
7
|
+
data.tar.gz: 16c1bb6ba7b910c86f8dc605980c393a8a4f10e0fa57eeeeb109b6fea25efaacb5125f14518666960fc0050ea82a3a64d2c8bd260db79a084522af4a701fc0f4
|
data/ffi/bolt/config.rb
CHANGED
@@ -3,10 +3,35 @@
|
|
3
3
|
module Bolt
|
4
4
|
module Config
|
5
5
|
extend Bolt::Library
|
6
|
+
typedef :int32_t, :bolt_scheme
|
7
|
+
typedef :int32_t, :bolt_transport
|
8
|
+
|
6
9
|
attach_function :create, :BoltConfig_create, [], :auto_pointer
|
7
10
|
attach_function :destroy, :BoltConfig_destroy, [:pointer], :void
|
11
|
+
attach_function :get_scheme, :BoltConfig_get_scheme, [:pointer], :bolt_scheme
|
12
|
+
attach_function :set_scheme, :BoltConfig_set_scheme, %i[pointer bolt_scheme], :int32_t
|
13
|
+
attach_function :get_transport, :BoltConfig_get_transport, [:pointer], :bolt_transport
|
14
|
+
attach_function :set_transport, :BoltConfig_set_transport, %i[pointer bolt_transport], :int32_t
|
15
|
+
attach_function :get_trust, :BoltConfig_get_trust, [:pointer], :pointer
|
16
|
+
attach_function :set_trust, :BoltConfig_set_trust, %i[pointer pointer], :int32_t
|
17
|
+
attach_function :get_user_agent, :BoltConfig_get_user_agent, [:pointer], :string
|
18
|
+
attach_function :set_user_agent, :BoltConfig_set_user_agent, %i[pointer string], :int32
|
19
|
+
attach_function :get_routing_context, :BoltConfig_get_routing_context, [:pointer], :pointer
|
20
|
+
attach_function :set_routing_context, :BoltConfig_set_routing_context, %i[pointer pointer], :int32_t
|
21
|
+
attach_function :get_address_resolver, :BoltConfig_get_address_resolver, [:pointer], :pointer
|
22
|
+
attach_function :set_address_resolver, :BoltConfig_set_address_resolver, %i[pointer pointer], :int32_t
|
8
23
|
attach_function :get_log, :BoltConfig_get_log, [:pointer], :pointer
|
9
24
|
attach_function :set_log, :BoltConfig_set_log, %i[pointer pointer], :int32
|
10
|
-
attach_function :
|
25
|
+
attach_function :get_max_pool_size, :BoltConfig_get_max_pool_size, [:pointer], :int32_t
|
26
|
+
attach_function :set_max_pool_size, :BoltConfig_set_max_pool_size, %i[pointer int32_t], :int32_t
|
27
|
+
attach_function :get_max_connection_life_time, :BoltConfig_get_max_connection_life_time, [:pointer], :int32_t
|
28
|
+
attach_function :set_max_connection_life_time, :BoltConfig_set_max_connection_life_time, %i[pointer int32_t],
|
29
|
+
:int32_t
|
30
|
+
attach_function :get_max_connection_acquisition_time, :BoltConfig_get_max_connection_acquisition_time, [:pointer],
|
31
|
+
:int32_t
|
32
|
+
attach_function :set_max_connection_acquisition_time, :BoltConfig_set_max_connection_acquisition_time,
|
33
|
+
%i[pointer int32_t], :int32_t
|
34
|
+
attach_function :get_socket_options, :BoltConfig_get_socket_options, [:pointer], :pointer
|
35
|
+
attach_function :set_socket_options, :BoltConfig_set_socket_options, %i[pointer pointer], :int32_t
|
11
36
|
end
|
12
37
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
module SocketOptions
|
5
|
+
extend Bolt::Library
|
6
|
+
|
7
|
+
attach_function :create, :BoltSocketOptions_create, [], :auto_pointer
|
8
|
+
attach_function :destroy, :BoltSocketOptions_destroy, [:pointer], :void
|
9
|
+
attach_function :get_connect_timeout, :BoltSocketOptions_get_connect_timeout, [:pointer], :int32_t
|
10
|
+
attach_function :set_connect_timeout, :BoltSocketOptions_set_connect_timeout, %i[pointer int32_t], :int32_t
|
11
|
+
attach_function :get_keep_alive, :BoltSocketOptions_get_keep_alive, [:pointer], :int32_t
|
12
|
+
attach_function :set_keep_alive, :BoltSocketOptions_set_keep_alive, %i[pointer int32_t], :int32_t
|
13
|
+
end
|
14
|
+
end
|
data/ffi/neo4j/driver.rb
CHANGED
data/ffi/neo4j/driver/config.rb
CHANGED
@@ -14,9 +14,9 @@ module Neo4j
|
|
14
14
|
|
15
15
|
auto_closable :driver
|
16
16
|
|
17
|
-
def driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, config =
|
17
|
+
def driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, config = nil)
|
18
18
|
raise Exceptions::AuthenticationException, 'Unsupported authentication token' unless auth_token
|
19
|
-
|
19
|
+
config ||= Config.default_config
|
20
20
|
# routing_settings = config.routing_settings
|
21
21
|
# retry_settings = config.retry_settings
|
22
22
|
routing_settings = nil
|
@@ -10,8 +10,9 @@ module Neo4j
|
|
10
10
|
attr_reader :protocol
|
11
11
|
attr_reader :bolt_connection
|
12
12
|
|
13
|
-
def initialize(connector, mode)
|
13
|
+
def initialize(connector, mode, config)
|
14
14
|
@connector = connector
|
15
|
+
@config = config
|
15
16
|
@bolt_connection = with_status { |status| Bolt::Connector.acquire(@connector, mode, status) }
|
16
17
|
|
17
18
|
# @protocol = Messaging::BoltProtocol.for_version(Bolt::Connection.server(bolt_connection).first)
|
@@ -6,12 +6,13 @@ module Neo4j
|
|
6
6
|
class DirectConnectionProvider
|
7
7
|
include ErrorHandling
|
8
8
|
|
9
|
-
def initialize(connector)
|
9
|
+
def initialize(connector, config)
|
10
10
|
@connector = connector
|
11
|
+
@config = config
|
11
12
|
end
|
12
13
|
|
13
14
|
def acquire_connection(mode)
|
14
|
-
Async::DirectConnection.new(@connector, mode)
|
15
|
+
Async::DirectConnection.new(@connector, mode, @config)
|
15
16
|
end
|
16
17
|
|
17
18
|
def verify_connectivity
|
@@ -13,7 +13,8 @@ module Neo4j
|
|
13
13
|
def new_instance(uri, auth_token, routing_settings, retry_settings, config)
|
14
14
|
uri = URI(uri)
|
15
15
|
connector, logger = create_connector(uri, auth_token, config)
|
16
|
-
|
16
|
+
retry_logic = Retry::ExponentialBackoffRetryLogic.new(config[:max_transaction_retry_time], config[:logger])
|
17
|
+
create_driver(uri.scheme, connector, logger, routing_settings, retry_logic, config).tap(&:verify_connectivity)
|
17
18
|
end
|
18
19
|
|
19
20
|
private
|
@@ -22,19 +23,37 @@ module Neo4j
|
|
22
23
|
address = Bolt::Address.create(host(uri).gsub(/^\[(.*)\]$/, '\\1'), port(uri).to_s)
|
23
24
|
bolt_config = bolt_config(config)
|
24
25
|
logger = InternalLogger.register(bolt_config, config[:logger])
|
26
|
+
set_socket_options(bolt_config, config)
|
25
27
|
[Bolt::Connector.create(address, auth_token, bolt_config), logger]
|
26
28
|
end
|
27
29
|
|
28
30
|
def bolt_config(config)
|
29
31
|
bolt_config = Bolt::Config.create
|
30
32
|
config.each do |key, value|
|
31
|
-
|
32
|
-
|
33
|
+
case key
|
34
|
+
when :max_connection_pool_size
|
35
|
+
check_error Bolt::Config.set_max_pool_size(bolt_config, value)
|
36
|
+
when :max_connection_life_time
|
37
|
+
check_error Bolt::Config.set_max_connection_life_time(bolt_config, value)
|
38
|
+
when :connection_acquisition_timeout
|
39
|
+
check_error Bolt::Config.set_max_connection_acquisition_time(bolt_config, value)
|
40
|
+
end
|
33
41
|
end
|
34
42
|
check_error Bolt::Config.set_user_agent(bolt_config, 'seabolt-cmake/1.7')
|
35
43
|
bolt_config
|
36
44
|
end
|
37
45
|
|
46
|
+
def set_socket_options(bolt_config, config)
|
47
|
+
socket_options = nil
|
48
|
+
config.each do |key, value|
|
49
|
+
case key
|
50
|
+
when :connection_timeout
|
51
|
+
check_error Bolt::SocketOptions.set_connect_timeout(socket_options ||= Bolt::SocketOptions.create, value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
check_error Bolt::Config.set_socket_options(bolt_config, socket_options) if socket_options
|
55
|
+
end
|
56
|
+
|
38
57
|
def host(uri)
|
39
58
|
uri.host.tap { |host| raise ArgumentError, "Invalid address format `#{uri}`" unless host }
|
40
59
|
end
|
@@ -44,12 +63,12 @@ module Neo4j
|
|
44
63
|
DEFAULT_PORT
|
45
64
|
end
|
46
65
|
|
47
|
-
def create_driver(scheme, connector, logger, routing_settings)
|
66
|
+
def create_driver(scheme, connector, logger, routing_settings, retry_logic, config)
|
48
67
|
case scheme
|
49
68
|
when BOLT_URI_SCHEME
|
50
69
|
# assert_no_routing_context( uri, routing_settings )
|
51
70
|
# return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metrics, config );
|
52
|
-
create_direct_driver(connector, logger)
|
71
|
+
create_direct_driver(connector, logger, retry_logic, config)
|
53
72
|
when BOLT_ROUTING_URI_SCHEME, NEO4J_URI_SCHEME
|
54
73
|
# create_routing_driver( security_plan, address, connection_ool, eventExecutorGroup, routingSettings, retryLogic, metrics, config );
|
55
74
|
else
|
@@ -57,9 +76,9 @@ module Neo4j
|
|
57
76
|
end
|
58
77
|
end
|
59
78
|
|
60
|
-
def create_direct_driver(connector, logger)
|
61
|
-
connection_provider = DirectConnectionProvider.new(connector)
|
62
|
-
session_factory = create_session_factory(connection_provider)
|
79
|
+
def create_direct_driver(connector, logger, retry_logic, config)
|
80
|
+
connection_provider = DirectConnectionProvider.new(connector, config)
|
81
|
+
session_factory = create_session_factory(connection_provider, retry_logic, config)
|
63
82
|
InternalDriver.new(session_factory, logger)
|
64
83
|
end
|
65
84
|
|
@@ -15,6 +15,13 @@ module Neo4j
|
|
15
15
|
# Connection refused
|
16
16
|
when Bolt::Error::BOLT_CONNECTION_REFUSED
|
17
17
|
throw Exceptions::ServiceUnavailableException.new(error_code, 'unable to acquire connection')
|
18
|
+
# Connection pool is full
|
19
|
+
when Bolt::Error::BOLT_POOL_FULL
|
20
|
+
throw Exceptions::ClientException.new(
|
21
|
+
error_code,
|
22
|
+
'Unable to acquire connection from the pool within configured maximum time of ' \
|
23
|
+
"#{@config[:connection_acquisition_timeout] * 1000}ms"
|
24
|
+
)
|
18
25
|
# Error set in connection
|
19
26
|
when Bolt::Error::BOLT_CONNECTION_HAS_MORE_INFO, Bolt::Error::BOLT_STATUS_SET
|
20
27
|
status = Bolt::Connection.status(bolt_connection)
|
@@ -37,6 +44,21 @@ module Neo4j
|
|
37
44
|
check_status(status)
|
38
45
|
end
|
39
46
|
|
47
|
+
def new_neo4j_error(code:, message:)
|
48
|
+
case code.split('.')[1]
|
49
|
+
when 'ClientError'
|
50
|
+
if code.casecmp('Neo.ClientError.Security.Unauthorized').zero?
|
51
|
+
Exceptions::AuthenticationException
|
52
|
+
else
|
53
|
+
Exceptions::ClientException
|
54
|
+
end
|
55
|
+
when 'TransientError'
|
56
|
+
Exceptions::TransientException
|
57
|
+
else
|
58
|
+
Exceptions::DatabaseException
|
59
|
+
end.new(code, message)
|
60
|
+
end
|
61
|
+
|
40
62
|
private
|
41
63
|
|
42
64
|
def throw(error)
|
@@ -5,6 +5,8 @@ module Neo4j
|
|
5
5
|
module Internal
|
6
6
|
module Handlers
|
7
7
|
class ResponseHandler
|
8
|
+
include ErrorHandling
|
9
|
+
|
8
10
|
delegate :bolt_connection, to: :connection
|
9
11
|
attr_reader :connection, :failure
|
10
12
|
attr_accessor :request, :previous
|
@@ -33,7 +35,7 @@ module Neo4j
|
|
33
35
|
else
|
34
36
|
return if previous&.failure
|
35
37
|
@failure = Value::ValueAdapter.to_ruby(Bolt::Connection.failure(bolt_connection))
|
36
|
-
raise
|
38
|
+
raise new_neo4j_error(@failure)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
@@ -15,12 +15,7 @@ module Neo4j
|
|
15
15
|
@open = Concurrent::AtomicBoolean.new(true)
|
16
16
|
@connection_provider = connection_provider
|
17
17
|
@mode = mode
|
18
|
-
|
19
|
-
@retry_logic = Class.new do
|
20
|
-
def retry
|
21
|
-
yield
|
22
|
-
end
|
23
|
-
end.new
|
18
|
+
@retry_logic = retry_logic
|
24
19
|
end
|
25
20
|
|
26
21
|
def run(statement, parameters = {}, config = nil)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Neo4j
|
4
|
+
module Driver
|
5
|
+
module Internal
|
6
|
+
module Retry
|
7
|
+
class ExponentialBackoffRetryLogic
|
8
|
+
DEFAULT_MAX_RETRY_TIME = 30
|
9
|
+
INITIAL_RETRY_DELAY = 1
|
10
|
+
RETRY_DELAY_MULTIPLIER = 2.0
|
11
|
+
RETRY_DELAY_JITTER_FACTOR = 0.2
|
12
|
+
|
13
|
+
def initialize(max_retry_time = nil, logger = nil)
|
14
|
+
@max_retry_time = max_retry_time || DEFAULT_MAX_RETRY_TIME
|
15
|
+
@log = logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def retry
|
19
|
+
next_delay = INITIAL_RETRY_DELAY
|
20
|
+
start_time = nil
|
21
|
+
errors = nil
|
22
|
+
loop do
|
23
|
+
return yield
|
24
|
+
rescue Exceptions::Neo4jException => error
|
25
|
+
if can_retry_on?(error)
|
26
|
+
curr_time = current_time
|
27
|
+
start_time ||= curr_time
|
28
|
+
elapsed_time = curr_time - start_time
|
29
|
+
if elapsed_time < @max_retry_time
|
30
|
+
delay_with_jitter = compute_delay_with_jitter(next_delay)
|
31
|
+
@log&.warn("Transaction failed and will be retried in #{delay_with_jitter}ms", error)
|
32
|
+
sleep(delay_with_jitter) # verify time units
|
33
|
+
next_delay *= RETRY_DELAY_MULTIPLIER
|
34
|
+
(errors ||= []) << error
|
35
|
+
next
|
36
|
+
end
|
37
|
+
end
|
38
|
+
add_suppressed(error, errors)
|
39
|
+
raise error
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def can_retry_on?(error)
|
46
|
+
error.is_a?(Exceptions::SessionExpiredException) ||
|
47
|
+
error.is_a?(Exceptions::ServiceUnavailableException) ||
|
48
|
+
transient_error?(error)
|
49
|
+
end
|
50
|
+
|
51
|
+
def transient_error?(error)
|
52
|
+
# Retries should not happen when transaction was explicitly terminated by the user.
|
53
|
+
# Termination of transaction might result in two different error codes depending on where it was
|
54
|
+
# terminated. These are really client errors but classification on the server is not entirely correct and
|
55
|
+
# they are classified as transient.
|
56
|
+
error.is_a?(Exceptions::TransientException) &&
|
57
|
+
!%w[Neo.TransientError.Transaction.Terminated Neo.TransientError.Transaction.LockClientStopped]
|
58
|
+
.include?(error.code)
|
59
|
+
end
|
60
|
+
|
61
|
+
def compute_delay_with_jitter(delay)
|
62
|
+
jitter = delay * RETRY_DELAY_JITTER_FACTOR
|
63
|
+
min = delay - jitter
|
64
|
+
max = delay + jitter
|
65
|
+
@rand ||= Random.new
|
66
|
+
@rand.rand(min..max)
|
67
|
+
end
|
68
|
+
|
69
|
+
def current_time
|
70
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_suppressed(error, suppressed_errors)
|
74
|
+
suppressed_errors&.reject(&error.method(:equal?))&.each(&error.method(:add_suppressed))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/neo4j/driver/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neo4j-ruby-driver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Heinrich Klobuczek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -239,11 +239,11 @@ files:
|
|
239
239
|
- ffi/bolt/lifecycle.rb
|
240
240
|
- ffi/bolt/list.rb
|
241
241
|
- ffi/bolt/log.rb
|
242
|
+
- ffi/bolt/socket_options.rb
|
242
243
|
- ffi/bolt/status.rb
|
243
244
|
- ffi/bolt/string.rb
|
244
245
|
- ffi/bolt/structure.rb
|
245
246
|
- ffi/bolt/value.rb
|
246
|
-
- ffi/bolt/values_private.rb
|
247
247
|
- ffi/neo4j/driver.rb
|
248
248
|
- ffi/neo4j/driver/access_mode.rb
|
249
249
|
- ffi/neo4j/driver/auth_tokens.rb
|
@@ -270,6 +270,7 @@ files:
|
|
270
270
|
- ffi/neo4j/driver/internal/messaging/v2/bolt_protocol_v2.rb
|
271
271
|
- ffi/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb
|
272
272
|
- ffi/neo4j/driver/internal/network_session.rb
|
273
|
+
- ffi/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb
|
273
274
|
- ffi/neo4j/driver/internal/session_factory_impl.rb
|
274
275
|
- ffi/neo4j/driver/internal/summary/internal_result_summary.rb
|
275
276
|
- ffi/neo4j/driver/internal/summary/internal_server_info.rb
|
data/ffi/bolt/values_private.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Bolt
|
4
|
-
module ValuesPrivate
|
5
|
-
extend FFI::Library
|
6
|
-
|
7
|
-
typedef :pointer, :bolt_value
|
8
|
-
# typedef BoltData, :bolt_data
|
9
|
-
# typedef BoltExtendedValue, :bolt_extended_value
|
10
|
-
#
|
11
|
-
# class BoltValue < FFI::Struct
|
12
|
-
# layout :type, :int16,
|
13
|
-
# :subtype, :int16,
|
14
|
-
# :size, :int16,
|
15
|
-
# :data_size, :uint64,
|
16
|
-
# :data, :bolt_data
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# class BoltData < FFI::Union
|
20
|
-
# layout :as_char, [:char, 16],
|
21
|
-
# :as_uint32, [:uint32, 4],
|
22
|
-
# :as_int8, [:int8_t, 16],
|
23
|
-
# :as_int16, [:int16, 8],
|
24
|
-
# :as_int32, [:int32, 4],
|
25
|
-
# :as_int64, [:int64, 2],
|
26
|
-
# :as_double, [:double, 2],
|
27
|
-
# :extended, :bolt_extended_value
|
28
|
-
# end
|
29
|
-
|
30
|
-
class BoltExtendedValue < FFI::Union
|
31
|
-
layout :as_ptr, :pointer,
|
32
|
-
:as_char, :string,
|
33
|
-
:as_value, :bolt_value
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|