makara 0.4.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|