makara 0.4.1 → 0.5.1
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 +5 -5
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/CI.yml +88 -0
- data/.github/workflows/gem-publish-public.yml +36 -0
- data/.rspec +1 -1
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +670 -0
- data/CHANGELOG.md +69 -48
- data/Gemfile +1 -16
- data/README.md +8 -9
- data/Rakefile +1 -1
- data/gemfiles/activerecord_5.2.gemfile +8 -0
- data/gemfiles/activerecord_6.0.gemfile +8 -0
- data/gemfiles/activerecord_6.1.gemfile +8 -0
- data/gemfiles/activerecord_head.gemfile +6 -0
- data/lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/makara_abstract_adapter.rb +107 -30
- data/lib/active_record/connection_adapters/makara_jdbcmysql_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/makara_jdbcpostgresql_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/makara_mysql2_adapter.rb +4 -20
- data/lib/active_record/connection_adapters/makara_postgis_adapter.rb +4 -19
- data/lib/active_record/connection_adapters/makara_postgresql_adapter.rb +4 -20
- data/lib/active_record/connection_adapters/mysql2_makara_adapter.rb +4 -20
- data/lib/active_record/connection_adapters/postgresql_makara_adapter.rb +4 -20
- data/lib/makara/cache.rb +0 -2
- data/lib/makara/config_parser.rb +7 -15
- data/lib/makara/connection_wrapper.rb +43 -22
- data/lib/makara/context.rb +1 -0
- data/lib/makara/cookie.rb +1 -0
- data/lib/makara/error_handler.rb +0 -9
- data/lib/makara/errors/all_connections_blacklisted.rb +0 -2
- data/lib/makara/errors/blacklist_connection.rb +0 -2
- data/lib/makara/errors/blacklisted_while_in_transaction.rb +12 -0
- data/lib/makara/errors/invalid_shard.rb +14 -0
- data/lib/makara/errors/makara_error.rb +0 -1
- data/lib/makara/errors/no_connections_available.rb +0 -2
- data/lib/makara/logging/logger.rb +0 -4
- data/lib/makara/logging/subscriber.rb +0 -2
- data/lib/makara/middleware.rb +1 -2
- data/lib/makara/pool.rb +49 -31
- data/lib/makara/proxy.rb +56 -30
- data/lib/makara/railtie.rb +0 -2
- data/lib/makara/strategies/abstract.rb +1 -0
- data/lib/makara/strategies/priority_failover.rb +2 -0
- data/lib/makara/strategies/round_robin.rb +1 -3
- data/lib/makara/strategies/shard_aware.rb +45 -0
- data/lib/makara/version.rb +1 -3
- data/lib/makara.rb +7 -6
- data/makara.gemspec +26 -3
- data/spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb +1 -6
- data/spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb +0 -9
- data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +9 -22
- data/spec/active_record/connection_adapters/makara_postgis_adapter_spec.rb +2 -10
- data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +62 -18
- data/spec/cache_spec.rb +0 -1
- data/spec/config_parser_spec.rb +54 -56
- data/spec/connection_wrapper_spec.rb +1 -2
- data/spec/cookie_spec.rb +4 -4
- data/spec/middleware_spec.rb +2 -2
- data/spec/pool_spec.rb +25 -14
- data/spec/proxy_spec.rb +0 -4
- data/spec/spec_helper.rb +6 -1
- data/spec/strategies/priority_failover_spec.rb +3 -4
- data/spec/strategies/round_robin_spec.rb +4 -8
- data/spec/strategies/shard_aware_spec.rb +218 -0
- data/spec/support/deep_dup.rb +1 -1
- data/spec/support/helpers.rb +5 -5
- data/spec/support/mock_objects.rb +5 -4
- data/spec/support/mysql2_database.yml +2 -2
- data/spec/support/mysql2_database_with_custom_errors.yml +2 -2
- data/spec/support/pool_extensions.rb +0 -3
- data/spec/support/postgis_schema.rb +1 -1
- data/spec/support/postgresql_database.yml +0 -2
- data/spec/support/proxy_extensions.rb +1 -3
- data/spec/support/schema.rb +1 -1
- data/spec/support/user.rb +1 -2
- metadata +165 -20
- data/.travis.yml +0 -105
- data/gemfiles/ar-head.gemfile +0 -24
- data/gemfiles/ar30.gemfile +0 -36
- data/gemfiles/ar31.gemfile +0 -36
- data/gemfiles/ar32.gemfile +0 -36
- data/gemfiles/ar40.gemfile +0 -24
- data/gemfiles/ar41.gemfile +0 -24
- data/gemfiles/ar42.gemfile +0 -24
- data/gemfiles/ar50.gemfile +0 -24
- data/gemfiles/ar51.gemfile +0 -24
data/lib/makara/middleware.rb
CHANGED
@@ -3,7 +3,6 @@ require 'rack'
|
|
3
3
|
# Persists the Makara::Context across requests ensuring the same master pool is used on subsequent requests.
|
4
4
|
module Makara
|
5
5
|
class Middleware
|
6
|
-
|
7
6
|
def initialize(app, cookie_options = {})
|
8
7
|
@app = app
|
9
8
|
@cookie_options = cookie_options
|
@@ -11,6 +10,7 @@ module Makara
|
|
11
10
|
|
12
11
|
def call(env)
|
13
12
|
return @app.call(env) if ignore_request?(env)
|
13
|
+
|
14
14
|
set_current_context(env)
|
15
15
|
|
16
16
|
status, headers, body = @app.call(env)
|
@@ -19,7 +19,6 @@ module Makara
|
|
19
19
|
[status, headers, body]
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
22
|
protected
|
24
23
|
|
25
24
|
def set_current_context(env)
|
data/lib/makara/pool.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
2
|
+
require 'makara/strategies/shard_aware'
|
2
3
|
|
3
4
|
# Wraps a collection of similar connections and chooses which one to use
|
4
5
|
# Provides convenience methods for accessing underlying connections
|
5
6
|
|
6
7
|
module Makara
|
7
8
|
class Pool
|
8
|
-
|
9
9
|
# there are cases when we understand the pool is busted and we essentially want to skip
|
10
10
|
# all execution
|
11
11
|
attr_accessor :disabled
|
@@ -13,6 +13,8 @@ module Makara
|
|
13
13
|
attr_reader :role
|
14
14
|
attr_reader :connections
|
15
15
|
attr_reader :strategy
|
16
|
+
attr_reader :shard_strategy_class
|
17
|
+
attr_reader :default_shard
|
16
18
|
|
17
19
|
def initialize(role, proxy)
|
18
20
|
@role = role
|
@@ -20,10 +22,15 @@ module Makara
|
|
20
22
|
@connections = []
|
21
23
|
@blacklist_errors = []
|
22
24
|
@disabled = false
|
23
|
-
|
25
|
+
if proxy.shard_aware_for(role)
|
26
|
+
@strategy = Makara::Strategies::ShardAware.new(self)
|
27
|
+
@shard_strategy_class = proxy.strategy_class_for(proxy.strategy_name_for(role))
|
28
|
+
@default_shard = proxy.default_shard_for(role)
|
29
|
+
else
|
30
|
+
@strategy = proxy.strategy_for(role)
|
31
|
+
end
|
24
32
|
end
|
25
33
|
|
26
|
-
|
27
34
|
def completely_blacklisted?
|
28
35
|
@connections.each do |connection|
|
29
36
|
return false unless connection._makara_blacklisted?
|
@@ -31,7 +38,6 @@ module Makara
|
|
31
38
|
true
|
32
39
|
end
|
33
40
|
|
34
|
-
|
35
41
|
# Add a connection to this pool, wrapping the connection with a Makara::ConnectionWrapper
|
36
42
|
def add(config)
|
37
43
|
config[:name] ||= "#{@role}/#{@connections.length + 1}"
|
@@ -61,6 +67,7 @@ module Makara
|
|
61
67
|
|
62
68
|
@connections.each do |con|
|
63
69
|
next if con._makara_blacklisted?
|
70
|
+
|
64
71
|
begin
|
65
72
|
ret = @proxy.error_handler.handle(con) do
|
66
73
|
if block
|
@@ -91,52 +98,63 @@ module Makara
|
|
91
98
|
# Provide a connection that is not blacklisted and connected. Handle any errors
|
92
99
|
# that may occur within the block.
|
93
100
|
def provide
|
94
|
-
|
101
|
+
attempt = 0
|
102
|
+
begin
|
103
|
+
provided_connection = self.next
|
95
104
|
|
96
|
-
|
97
|
-
|
105
|
+
# nil implies that it's blacklisted
|
106
|
+
if provided_connection
|
98
107
|
|
99
|
-
|
100
|
-
|
101
|
-
|
108
|
+
value = @proxy.error_handler.handle(provided_connection) do
|
109
|
+
yield provided_connection
|
110
|
+
end
|
102
111
|
|
103
|
-
|
112
|
+
@blacklist_errors = []
|
104
113
|
|
105
|
-
|
114
|
+
value
|
106
115
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
116
|
+
# if we've made any connections within this pool, we should report the blackout.
|
117
|
+
elsif connection_made?
|
118
|
+
err = Makara::Errors::AllConnectionsBlacklisted.new(self, @blacklist_errors)
|
119
|
+
@blacklist_errors = []
|
120
|
+
raise err
|
121
|
+
else
|
122
|
+
raise Makara::Errors::NoConnectionsAvailable.new(@role) unless @disabled
|
123
|
+
end
|
115
124
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
125
|
+
# when a connection causes a blacklist error within the provided block, we blacklist it then retry
|
126
|
+
rescue Makara::Errors::BlacklistConnection => e
|
127
|
+
@blacklist_errors.insert(0, e)
|
128
|
+
in_transaction = self.role == "master" && provided_connection._makara_in_transaction?
|
129
|
+
provided_connection._makara_blacklist!
|
130
|
+
raise Makara::Errors::BlacklistedWhileInTransaction.new(@role) if in_transaction
|
131
|
+
|
132
|
+
attempt += 1
|
133
|
+
if attempt < @connections.length
|
134
|
+
retry
|
135
|
+
elsif connection_made?
|
136
|
+
err = Makara::Errors::AllConnectionsBlacklisted.new(self, @blacklist_errors)
|
137
|
+
@blacklist_errors = []
|
138
|
+
raise err
|
139
|
+
else
|
140
|
+
raise Makara::Errors::NoConnectionsAvailable.new(@role) unless @disabled
|
141
|
+
end
|
142
|
+
end
|
121
143
|
end
|
122
144
|
|
123
|
-
|
124
|
-
|
125
145
|
protected
|
126
146
|
|
127
|
-
|
128
147
|
# have we connected to any of the underlying connections.
|
129
148
|
def connection_made?
|
130
149
|
@connections.any?(&:_makara_connected?)
|
131
150
|
end
|
132
151
|
|
133
|
-
|
134
152
|
# Get the next non-blacklisted connection. If the proxy is setup
|
135
153
|
# to be sticky, provide back the current connection assuming it is
|
136
154
|
# not blacklisted.
|
137
155
|
def next
|
138
|
-
if @proxy.sticky && @strategy.current
|
139
|
-
|
156
|
+
if @proxy.sticky && (curr = @strategy.current)
|
157
|
+
curr
|
140
158
|
else
|
141
159
|
@strategy.next
|
142
160
|
end
|
data/lib/makara/proxy.rb
CHANGED
@@ -11,11 +11,11 @@ require 'active_support/core_ext/string/inflections'
|
|
11
11
|
|
12
12
|
module Makara
|
13
13
|
class Proxy < ::SimpleDelegator
|
14
|
-
|
15
14
|
METHOD_MISSING_SKIP = [ :byebug, :puts ]
|
16
15
|
|
17
|
-
class_attribute :hijack_methods
|
16
|
+
class_attribute :hijack_methods, :control_methods
|
18
17
|
self.hijack_methods = []
|
18
|
+
self.control_methods = []
|
19
19
|
|
20
20
|
class << self
|
21
21
|
def hijack_method(*method_names)
|
@@ -23,27 +23,44 @@ module Makara
|
|
23
23
|
self.hijack_methods |= method_names
|
24
24
|
|
25
25
|
method_names.each do |method_name|
|
26
|
-
define_method
|
26
|
+
define_method(method_name) do |*args, &block|
|
27
27
|
appropriate_connection(method_name, args) do |con|
|
28
28
|
con.send(method_name, *args, &block)
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
36
|
def send_to_all(*method_names)
|
35
37
|
method_names.each do |method_name|
|
36
|
-
define_method
|
37
|
-
send_to_all
|
38
|
+
define_method(method_name) do |*args|
|
39
|
+
send_to_all(method_name, *args)
|
38
40
|
end
|
41
|
+
|
42
|
+
ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
|
39
43
|
end
|
40
44
|
end
|
41
|
-
end
|
42
45
|
|
46
|
+
def control_method(*method_names)
|
47
|
+
self.control_methods = self.control_methods || []
|
48
|
+
self.control_methods |= method_names
|
49
|
+
|
50
|
+
method_names.each do |method_name|
|
51
|
+
define_method(method_name) do |*args, &block|
|
52
|
+
control&.send(method_name, *args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
43
59
|
|
44
60
|
attr_reader :error_handler
|
45
61
|
attr_reader :sticky
|
46
62
|
attr_reader :config_parser
|
63
|
+
attr_reader :control
|
47
64
|
|
48
65
|
def initialize(config)
|
49
66
|
@config = config.symbolize_keys
|
@@ -84,6 +101,14 @@ module Makara
|
|
84
101
|
@config_parser.makara_config["#{role}_strategy".to_sym]
|
85
102
|
end
|
86
103
|
|
104
|
+
def shard_aware_for(role)
|
105
|
+
@config_parser.makara_config["#{role}_shard_aware".to_sym]
|
106
|
+
end
|
107
|
+
|
108
|
+
def default_shard_for(role)
|
109
|
+
@config_parser.makara_config["#{role}_default_shard".to_sym]
|
110
|
+
end
|
111
|
+
|
87
112
|
def strategy_class_for(strategy_name)
|
88
113
|
case strategy_name
|
89
114
|
when 'round_robin', 'roundrobin', nil, ''
|
@@ -97,27 +122,25 @@ module Makara
|
|
97
122
|
|
98
123
|
def method_missing(m, *args, &block)
|
99
124
|
if METHOD_MISSING_SKIP.include?(m)
|
100
|
-
return super
|
125
|
+
return super
|
101
126
|
end
|
102
127
|
|
103
128
|
any_connection do |con|
|
104
|
-
if con.respond_to?(m)
|
105
|
-
con.
|
106
|
-
elsif con.respond_to?(m, true)
|
107
|
-
con.__send__(m, *args, &block)
|
129
|
+
if con.respond_to?(m, true)
|
130
|
+
con.send(m, *args, &block)
|
108
131
|
else
|
109
|
-
super
|
132
|
+
super
|
110
133
|
end
|
111
134
|
end
|
112
135
|
end
|
113
136
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
137
|
+
ruby2_keywords :method_missing if Module.private_method_defined?(:ruby2_keywords)
|
138
|
+
|
139
|
+
def respond_to_missing?(m, include_private = false)
|
140
|
+
any_connection do |con|
|
141
|
+
con._makara_connection.respond_to?(m, true)
|
119
142
|
end
|
120
|
-
|
143
|
+
end
|
121
144
|
|
122
145
|
def graceful_connection_for(config)
|
123
146
|
fake_wrapper = Makara::ConnectionWrapper.new(self, nil, config)
|
@@ -138,18 +161,25 @@ module Makara
|
|
138
161
|
|
139
162
|
protected
|
140
163
|
|
141
|
-
|
142
164
|
def send_to_all(method_name, *args)
|
143
165
|
# slave pool must run first to allow for slave-->master failover without running operations on master twice.
|
144
166
|
handling_an_all_execution(method_name) do
|
145
|
-
@slave_pool.send_to_all
|
146
|
-
@master_pool.send_to_all
|
167
|
+
@slave_pool.send_to_all(method_name, *args)
|
168
|
+
@master_pool.send_to_all(method_name, *args)
|
147
169
|
end
|
148
170
|
end
|
149
171
|
|
172
|
+
ruby2_keywords :send_to_all if Module.private_method_defined?(:ruby2_keywords)
|
173
|
+
|
150
174
|
def any_connection
|
151
|
-
@master_pool.
|
152
|
-
|
175
|
+
if @master_pool.disabled
|
176
|
+
@slave_pool.provide do |con|
|
177
|
+
yield con
|
178
|
+
end
|
179
|
+
else
|
180
|
+
@master_pool.provide do |con|
|
181
|
+
yield con
|
182
|
+
end
|
153
183
|
end
|
154
184
|
rescue ::Makara::Errors::AllConnectionsBlacklisted, ::Makara::Errors::NoConnectionsAvailable
|
155
185
|
begin
|
@@ -175,14 +205,11 @@ module Makara
|
|
175
205
|
end
|
176
206
|
end
|
177
207
|
|
178
|
-
|
179
208
|
# master or slave
|
180
209
|
def appropriate_pool(method_name, args)
|
181
|
-
|
182
210
|
# for testing purposes
|
183
211
|
pool = _appropriate_pool(method_name, args)
|
184
212
|
yield pool
|
185
|
-
|
186
213
|
rescue ::Makara::Errors::AllConnectionsBlacklisted, ::Makara::Errors::NoConnectionsAvailable => e
|
187
214
|
if pool == @master_pool
|
188
215
|
@master_pool.connections.each(&:_makara_whitelist!)
|
@@ -241,7 +268,6 @@ module Makara
|
|
241
268
|
@hijacked = false
|
242
269
|
end
|
243
270
|
|
244
|
-
|
245
271
|
def stuck_to_master?
|
246
272
|
sticky? && Makara::Context.stuck?(@id)
|
247
273
|
end
|
@@ -286,18 +312,18 @@ module Makara
|
|
286
312
|
yield
|
287
313
|
rescue ::Makara::Errors::NoConnectionsAvailable => e
|
288
314
|
if e.role == 'master'
|
289
|
-
|
315
|
+
# this means slave connections are good.
|
316
|
+
return
|
290
317
|
end
|
318
|
+
|
291
319
|
@slave_pool.disabled = true
|
292
320
|
yield
|
293
321
|
ensure
|
294
322
|
@slave_pool.disabled = false
|
295
323
|
end
|
296
324
|
|
297
|
-
|
298
325
|
def connection_for(config)
|
299
326
|
Kernel.raise NotImplementedError
|
300
327
|
end
|
301
|
-
|
302
328
|
end
|
303
329
|
end
|
data/lib/makara/railtie.rb
CHANGED
@@ -27,6 +27,7 @@ module Makara
|
|
27
27
|
@weighted_connections.each_with_index do |con, index|
|
28
28
|
check = safe_value(index)
|
29
29
|
next unless check
|
30
|
+
|
30
31
|
@current_idx = index
|
31
32
|
return check
|
32
33
|
end
|
@@ -41,6 +42,7 @@ module Makara
|
|
41
42
|
con = @weighted_connections[idx]
|
42
43
|
return nil unless con
|
43
44
|
return nil if con._makara_blacklisted?
|
45
|
+
|
44
46
|
con
|
45
47
|
end
|
46
48
|
end
|
@@ -26,8 +26,8 @@ module Makara
|
|
26
26
|
return safe_value(0, true) if single_one?
|
27
27
|
|
28
28
|
idx = @current_idx
|
29
|
-
begin
|
30
29
|
|
30
|
+
begin
|
31
31
|
idx = next_index(idx)
|
32
32
|
|
33
33
|
# if we've looped all the way around, return our safe value
|
@@ -48,7 +48,6 @@ module Makara
|
|
48
48
|
idx
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
51
|
# return the connection if it's not blacklisted
|
53
52
|
# otherwise return nil
|
54
53
|
# optionally, store the position and context we're returning
|
@@ -64,7 +63,6 @@ module Makara
|
|
64
63
|
con
|
65
64
|
end
|
66
65
|
|
67
|
-
|
68
66
|
# stub in test mode to ensure consistency
|
69
67
|
def should_shuffle?
|
70
68
|
true
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'makara/errors/invalid_shard'
|
2
|
+
|
3
|
+
module Makara
|
4
|
+
module Strategies
|
5
|
+
class ShardAware < ::Makara::Strategies::Abstract
|
6
|
+
def init
|
7
|
+
@shards = {}
|
8
|
+
@default_shard = pool.default_shard
|
9
|
+
end
|
10
|
+
|
11
|
+
def connection_added(wrapper)
|
12
|
+
id = wrapper._makara_shard_id
|
13
|
+
shard_strategy(id).connection_added(wrapper)
|
14
|
+
end
|
15
|
+
|
16
|
+
def shard_strategy(shard_id)
|
17
|
+
id = shard_id
|
18
|
+
shard_strategy = @shards[id]
|
19
|
+
unless shard_strategy
|
20
|
+
shard_strategy = pool.shard_strategy_class.new(pool)
|
21
|
+
@shards[id] = shard_strategy
|
22
|
+
end
|
23
|
+
shard_strategy
|
24
|
+
end
|
25
|
+
|
26
|
+
def current
|
27
|
+
id = shard_id
|
28
|
+
raise Makara::Errors::InvalidShard.new(pool.role, id) unless id && @shards[id]
|
29
|
+
|
30
|
+
@shards[id].current
|
31
|
+
end
|
32
|
+
|
33
|
+
def next
|
34
|
+
id = shard_id
|
35
|
+
raise Makara::Errors::InvalidShard.new(pool.role, id) unless id && @shards[id]
|
36
|
+
|
37
|
+
@shards[id].next
|
38
|
+
end
|
39
|
+
|
40
|
+
def shard_id
|
41
|
+
Thread.current['makara_shard_id'] || pool.default_shard
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/makara/version.rb
CHANGED
data/lib/makara.rb
CHANGED
@@ -2,7 +2,6 @@ require 'active_support'
|
|
2
2
|
require 'makara/version'
|
3
3
|
require 'makara/railtie' if defined?(Rails)
|
4
4
|
module Makara
|
5
|
-
|
6
5
|
autoload :Cache, 'makara/cache'
|
7
6
|
autoload :ConfigParser, 'makara/config_parser'
|
8
7
|
autoload :ConnectionWrapper, 'makara/connection_wrapper'
|
@@ -14,10 +13,12 @@ module Makara
|
|
14
13
|
autoload :Proxy, 'makara/proxy'
|
15
14
|
|
16
15
|
module Errors
|
17
|
-
autoload :MakaraError,
|
18
|
-
autoload :AllConnectionsBlacklisted,
|
19
|
-
autoload :BlacklistConnection,
|
20
|
-
autoload :NoConnectionsAvailable,
|
16
|
+
autoload :MakaraError, 'makara/errors/makara_error'
|
17
|
+
autoload :AllConnectionsBlacklisted, 'makara/errors/all_connections_blacklisted'
|
18
|
+
autoload :BlacklistConnection, 'makara/errors/blacklist_connection'
|
19
|
+
autoload :NoConnectionsAvailable, 'makara/errors/no_connections_available'
|
20
|
+
autoload :BlacklistedWhileInTransaction, 'makara/errors/blacklisted_while_in_transaction'
|
21
|
+
autoload :InvalidShard, 'makara/errors/invalid_shard'
|
21
22
|
end
|
22
23
|
|
23
24
|
module Logging
|
@@ -29,8 +30,8 @@ module Makara
|
|
29
30
|
autoload :Abstract, 'makara/strategies/abstract'
|
30
31
|
autoload :RoundRobin, 'makara/strategies/round_robin'
|
31
32
|
autoload :PriorityFailover, 'makara/strategies/priority_failover'
|
33
|
+
autoload :ShardAware, 'makara/strategies/shard_aware'
|
32
34
|
end
|
33
|
-
|
34
35
|
end
|
35
36
|
|
36
37
|
ActiveSupport.on_load(:active_record) do
|
data/makara.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
require File.expand_path('../lib/makara/version', __FILE__)
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
@@ -6,7 +5,11 @@ Gem::Specification.new do |gem|
|
|
6
5
|
gem.email = ["mike@mikeonrails.com"]
|
7
6
|
gem.description = %q{Read-write split your DB yo}
|
8
7
|
gem.summary = %q{Read-write split your DB yo}
|
9
|
-
gem.homepage = ""
|
8
|
+
gem.homepage = "https://github.com/instacart/makara"
|
9
|
+
gem.licenses = ['MIT']
|
10
|
+
gem.metadata = {
|
11
|
+
"source_code_uri" => 'https://github.com/instacart/makara'
|
12
|
+
}
|
10
13
|
|
11
14
|
gem.files = `git ls-files`.split($\)
|
12
15
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -15,5 +18,25 @@ Gem::Specification.new do |gem|
|
|
15
18
|
gem.require_paths = ["lib"]
|
16
19
|
gem.version = Makara::VERSION
|
17
20
|
|
18
|
-
gem.
|
21
|
+
gem.required_ruby_version = ">= 2.5.0"
|
22
|
+
|
23
|
+
gem.add_dependency "activerecord", ">= 5.2.0"
|
24
|
+
|
25
|
+
gem.add_development_dependency "rack"
|
26
|
+
gem.add_development_dependency "rake", "~> 13.0"
|
27
|
+
gem.add_development_dependency "rspec", "~> 3.9"
|
28
|
+
gem.add_development_dependency "timecop"
|
29
|
+
gem.add_development_dependency "rubocop", "~> 1.9.1"
|
30
|
+
|
31
|
+
if RUBY_ENGINE == "jruby"
|
32
|
+
gem.add_development_dependency "activerecord-jdbcmysql-adapter"
|
33
|
+
gem.add_development_dependency "activerecord-jdbcpostgresql-adapter"
|
34
|
+
gem.add_development_dependency "ruby-debug"
|
35
|
+
else
|
36
|
+
gem.add_development_dependency "activerecord-postgis-adapter"
|
37
|
+
gem.add_development_dependency "pry-byebug"
|
38
|
+
gem.add_development_dependency "mysql2"
|
39
|
+
gem.add_development_dependency "pg"
|
40
|
+
gem.add_development_dependency "rgeo"
|
41
|
+
end
|
19
42
|
end
|
@@ -2,7 +2,6 @@ require 'spec_helper'
|
|
2
2
|
require 'active_record/connection_adapters/makara_abstract_adapter'
|
3
3
|
|
4
4
|
describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter::ErrorHandler do
|
5
|
-
|
6
5
|
let(:handler){ described_class.new }
|
7
6
|
let(:proxy) { FakeAdapter.new(config(1,1)) }
|
8
7
|
let(:connection){ proxy.master_pool.connections.first }
|
@@ -60,9 +59,8 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter::ErrorHandler d
|
|
60
59
|
end
|
61
60
|
|
62
61
|
describe 'custom errors' do
|
63
|
-
|
64
62
|
let(:config_path) { File.join(File.expand_path('../../../', __FILE__), 'support', 'mysql2_database_with_custom_errors.yml') }
|
65
|
-
let(:config) { YAML.
|
63
|
+
let(:config) { YAML.load(ERB.new(File.read(config_path)).result)['test'] }
|
66
64
|
let(:handler){ described_class.new }
|
67
65
|
let(:proxy) { FakeAdapter.new(config) }
|
68
66
|
let(:connection){ proxy.master_pool.connections.first }
|
@@ -85,8 +83,5 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter::ErrorHandler d
|
|
85
83
|
end
|
86
84
|
}.to raise_error(Makara::Errors::BlacklistConnection)
|
87
85
|
end
|
88
|
-
|
89
86
|
end
|
90
|
-
|
91
|
-
|
92
87
|
end
|
@@ -2,7 +2,6 @@ require 'spec_helper'
|
|
2
2
|
require 'active_record/connection_adapters/makara_abstract_adapter'
|
3
3
|
|
4
4
|
describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
|
5
|
-
|
6
5
|
let(:klass){ FakeAdapter }
|
7
6
|
|
8
7
|
{
|
@@ -38,15 +37,12 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
|
|
38
37
|
'select pg_advisory_lock(12345)' => true,
|
39
38
|
'select pg_advisory_unlock(12345)' => true
|
40
39
|
}.each do |sql, should_go_to_master|
|
41
|
-
|
42
40
|
it "determines that \"#{sql}\" #{should_go_to_master ? 'requires' : 'does not require'} master" do
|
43
41
|
proxy = klass.new(config(1,1))
|
44
42
|
expect(proxy.master_for?(sql)).to eq(should_go_to_master)
|
45
43
|
end
|
46
|
-
|
47
44
|
end
|
48
45
|
|
49
|
-
|
50
46
|
{
|
51
47
|
"SET @@things" => true,
|
52
48
|
"INSERT INTO wisdom ('The truth will set you free.')" => false,
|
@@ -61,7 +57,6 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
|
|
61
57
|
max_treats IS NULL
|
62
58
|
} => false
|
63
59
|
}.each do |sql, should_send_to_all_connections|
|
64
|
-
|
65
60
|
it "determines that \"#{sql}\" #{should_send_to_all_connections ? 'should' : 'should not'} be sent to all underlying connections" do
|
66
61
|
proxy = klass.new(config(1,1))
|
67
62
|
proxy.master_pool.connections.each{|con| expect(con).to receive(:execute).with(sql).once}
|
@@ -75,7 +70,6 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
|
|
75
70
|
|
76
71
|
proxy.execute(sql)
|
77
72
|
end
|
78
|
-
|
79
73
|
end
|
80
74
|
|
81
75
|
{
|
@@ -108,12 +102,9 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
|
|
108
102
|
max_treats IS NULL
|
109
103
|
} => true
|
110
104
|
}.each do |sql,should_stick|
|
111
|
-
|
112
105
|
it "should #{should_stick ? 'stick' : 'not stick'} to master if handling sql like \"#{sql}\"" do
|
113
106
|
proxy = klass.new(config(0,0))
|
114
107
|
expect(proxy.would_stick?(sql)).to eq(should_stick)
|
115
108
|
end
|
116
|
-
|
117
109
|
end
|
118
|
-
|
119
110
|
end
|