makara 0.5.0 → 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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/CI.yml +88 -0
  4. data/.rspec +1 -1
  5. data/.rubocop.yml +15 -0
  6. data/.rubocop_todo.yml +670 -0
  7. data/CHANGELOG.md +14 -6
  8. data/Gemfile +1 -16
  9. data/README.md +2 -1
  10. data/Rakefile +1 -1
  11. data/gemfiles/activerecord_5.2.gemfile +8 -0
  12. data/gemfiles/activerecord_6.0.gemfile +8 -0
  13. data/gemfiles/activerecord_6.1.gemfile +8 -0
  14. data/gemfiles/activerecord_head.gemfile +6 -0
  15. data/lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb +4 -18
  16. data/lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb +4 -18
  17. data/lib/active_record/connection_adapters/makara_abstract_adapter.rb +3 -31
  18. data/lib/active_record/connection_adapters/makara_jdbcmysql_adapter.rb +4 -18
  19. data/lib/active_record/connection_adapters/makara_jdbcpostgresql_adapter.rb +4 -18
  20. data/lib/active_record/connection_adapters/makara_mysql2_adapter.rb +4 -20
  21. data/lib/active_record/connection_adapters/makara_postgis_adapter.rb +4 -19
  22. data/lib/active_record/connection_adapters/makara_postgresql_adapter.rb +4 -20
  23. data/lib/active_record/connection_adapters/mysql2_makara_adapter.rb +4 -20
  24. data/lib/active_record/connection_adapters/postgresql_makara_adapter.rb +4 -20
  25. data/lib/makara.rb +0 -2
  26. data/lib/makara/cache.rb +0 -2
  27. data/lib/makara/config_parser.rb +5 -14
  28. data/lib/makara/connection_wrapper.rb +24 -27
  29. data/lib/makara/context.rb +1 -0
  30. data/lib/makara/cookie.rb +1 -0
  31. data/lib/makara/error_handler.rb +0 -9
  32. data/lib/makara/errors/all_connections_blacklisted.rb +0 -2
  33. data/lib/makara/errors/blacklist_connection.rb +0 -2
  34. data/lib/makara/errors/blacklisted_while_in_transaction.rb +0 -2
  35. data/lib/makara/errors/invalid_shard.rb +1 -3
  36. data/lib/makara/errors/makara_error.rb +0 -1
  37. data/lib/makara/errors/no_connections_available.rb +0 -2
  38. data/lib/makara/logging/logger.rb +0 -4
  39. data/lib/makara/logging/subscriber.rb +0 -2
  40. data/lib/makara/middleware.rb +1 -2
  41. data/lib/makara/pool.rb +2 -7
  42. data/lib/makara/proxy.rb +25 -27
  43. data/lib/makara/railtie.rb +0 -2
  44. data/lib/makara/strategies/abstract.rb +1 -0
  45. data/lib/makara/strategies/priority_failover.rb +2 -0
  46. data/lib/makara/strategies/round_robin.rb +1 -3
  47. data/lib/makara/strategies/shard_aware.rb +0 -2
  48. data/lib/makara/version.rb +1 -3
  49. data/makara.gemspec +24 -5
  50. data/spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb +1 -6
  51. data/spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb +0 -9
  52. data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +9 -22
  53. data/spec/active_record/connection_adapters/makara_postgis_adapter_spec.rb +2 -10
  54. data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +7 -20
  55. data/spec/cache_spec.rb +0 -1
  56. data/spec/config_parser_spec.rb +54 -56
  57. data/spec/connection_wrapper_spec.rb +1 -2
  58. data/spec/cookie_spec.rb +1 -1
  59. data/spec/middleware_spec.rb +1 -1
  60. data/spec/pool_spec.rb +3 -16
  61. data/spec/proxy_spec.rb +0 -4
  62. data/spec/spec_helper.rb +5 -1
  63. data/spec/strategies/priority_failover_spec.rb +3 -4
  64. data/spec/strategies/round_robin_spec.rb +4 -8
  65. data/spec/strategies/shard_aware_spec.rb +4 -5
  66. data/spec/support/deep_dup.rb +1 -1
  67. data/spec/support/helpers.rb +5 -5
  68. data/spec/support/mock_objects.rb +1 -4
  69. data/spec/support/mysql2_database.yml +2 -2
  70. data/spec/support/mysql2_database_with_custom_errors.yml +2 -2
  71. data/spec/support/pool_extensions.rb +0 -3
  72. data/spec/support/postgis_schema.rb +1 -1
  73. data/spec/support/postgresql_database.yml +0 -2
  74. data/spec/support/proxy_extensions.rb +1 -3
  75. data/spec/support/schema.rb +1 -1
  76. data/spec/support/user.rb +1 -2
  77. metadata +156 -20
  78. data/.travis.yml +0 -131
  79. data/gemfiles/ar-head.gemfile +0 -24
  80. data/gemfiles/ar30.gemfile +0 -36
  81. data/gemfiles/ar31.gemfile +0 -36
  82. data/gemfiles/ar32.gemfile +0 -36
  83. data/gemfiles/ar40.gemfile +0 -24
  84. data/gemfiles/ar41.gemfile +0 -24
  85. data/gemfiles/ar42.gemfile +0 -24
  86. data/gemfiles/ar50.gemfile +0 -24
  87. data/gemfiles/ar51.gemfile +0 -24
  88. data/gemfiles/ar52.gemfile +0 -24
  89. data/gemfiles/ar60.gemfile +0 -24
@@ -1,14 +1,12 @@
1
1
  module Makara
2
2
  module Errors
3
3
  class BlacklistConnection < MakaraError
4
-
5
4
  attr_reader :original_error
6
5
 
7
6
  def initialize(connection, error)
8
7
  @original_error = error
9
8
  super "[Makara/#{connection._makara_name}] #{error.message}"
10
9
  end
11
-
12
10
  end
13
11
  end
14
12
  end
@@ -1,14 +1,12 @@
1
1
  module Makara
2
2
  module Errors
3
3
  class BlacklistedWhileInTransaction < MakaraError
4
-
5
4
  attr_reader :role
6
5
 
7
6
  def initialize(role)
8
7
  @role = role
9
8
  super "[Makara] Blacklisted while in transaction in the #{role} pool"
10
9
  end
11
-
12
10
  end
13
11
  end
14
12
  end
@@ -1,7 +1,6 @@
1
1
  module Makara
2
2
  module Errors
3
3
  class InvalidShard < MakaraError
4
-
5
4
  attr_reader :role
6
5
  attr_reader :shard_id
7
6
 
@@ -10,7 +9,6 @@ module Makara
10
9
  @shard_id = shard_id
11
10
  super "[Makara] Invalid shard_id #{shard_id} for the #{role} pool"
12
11
  end
13
-
14
12
  end
15
13
  end
16
- end
14
+ end
@@ -1,7 +1,6 @@
1
1
  module Makara
2
2
  module Errors
3
3
  class MakaraError < ::ActiveRecord::ActiveRecordError
4
-
5
4
  end
6
5
  end
7
6
  end
@@ -1,14 +1,12 @@
1
1
  module Makara
2
2
  module Errors
3
3
  class NoConnectionsAvailable < MakaraError
4
-
5
4
  attr_reader :role
6
5
 
7
6
  def initialize(role)
8
7
  @role = role
9
8
  super "[Makara] No connections are available in the #{role} pool"
10
9
  end
11
-
12
10
  end
13
11
  end
14
12
  end
@@ -1,9 +1,7 @@
1
1
  module Makara
2
2
  module Logging
3
3
  class Logger
4
-
5
4
  class << self
6
-
7
5
  def log(msg, format = :error)
8
6
  logger.send(format, "[Makara] #{msg}") if logger
9
7
  end
@@ -15,9 +13,7 @@ module Makara
15
13
  def logger=(l)
16
14
  @logger = l
17
15
  end
18
-
19
16
  end
20
-
21
17
  end
22
18
  end
23
19
  end
@@ -1,6 +1,5 @@
1
1
  module Makara
2
2
  module Logging
3
-
4
3
  module Subscriber
5
4
  IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
6
5
 
@@ -33,6 +32,5 @@ module Makara
33
32
  "[#{adapter._makara_name}]"
34
33
  end
35
34
  end
36
-
37
35
  end
38
36
  end
@@ -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
@@ -6,7 +6,6 @@ require 'makara/strategies/shard_aware'
6
6
 
7
7
  module Makara
8
8
  class Pool
9
-
10
9
  # there are cases when we understand the pool is busted and we essentially want to skip
11
10
  # all execution
12
11
  attr_accessor :disabled
@@ -32,7 +31,6 @@ module Makara
32
31
  end
33
32
  end
34
33
 
35
-
36
34
  def completely_blacklisted?
37
35
  @connections.each do |connection|
38
36
  return false unless connection._makara_blacklisted?
@@ -40,7 +38,6 @@ module Makara
40
38
  true
41
39
  end
42
40
 
43
-
44
41
  # Add a connection to this pool, wrapping the connection with a Makara::ConnectionWrapper
45
42
  def add(config)
46
43
  config[:name] ||= "#{@role}/#{@connections.length + 1}"
@@ -70,6 +67,7 @@ module Makara
70
67
 
71
68
  @connections.each do |con|
72
69
  next if con._makara_blacklisted?
70
+
73
71
  begin
74
72
  ret = @proxy.error_handler.handle(con) do
75
73
  if block
@@ -130,6 +128,7 @@ module Makara
130
128
  in_transaction = self.role == "master" && provided_connection._makara_in_transaction?
131
129
  provided_connection._makara_blacklist!
132
130
  raise Makara::Errors::BlacklistedWhileInTransaction.new(@role) if in_transaction
131
+
133
132
  attempt += 1
134
133
  if attempt < @connections.length
135
134
  retry
@@ -143,17 +142,13 @@ module Makara
143
142
  end
144
143
  end
145
144
 
146
-
147
-
148
145
  protected
149
146
 
150
-
151
147
  # have we connected to any of the underlying connections.
152
148
  def connection_made?
153
149
  @connections.any?(&:_makara_connected?)
154
150
  end
155
151
 
156
-
157
152
  # Get the next non-blacklisted connection. If the proxy is setup
158
153
  # to be sticky, provide back the current connection assuming it is
159
154
  # not blacklisted.
data/lib/makara/proxy.rb CHANGED
@@ -11,7 +11,6 @@ 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
16
  class_attribute :hijack_methods, :control_methods
@@ -24,19 +23,23 @@ module Makara
24
23
  self.hijack_methods |= method_names
25
24
 
26
25
  method_names.each do |method_name|
27
- define_method method_name do |*args, &block|
26
+ define_method(method_name) do |*args, &block|
28
27
  appropriate_connection(method_name, args) do |con|
29
28
  con.send(method_name, *args, &block)
30
29
  end
31
30
  end
31
+
32
+ ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
32
33
  end
33
34
  end
34
35
 
35
36
  def send_to_all(*method_names)
36
37
  method_names.each do |method_name|
37
- define_method method_name do |*args|
38
- send_to_all method_name, *args
38
+ define_method(method_name) do |*args|
39
+ send_to_all(method_name, *args)
39
40
  end
41
+
42
+ ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
40
43
  end
41
44
  end
42
45
 
@@ -45,14 +48,15 @@ module Makara
45
48
  self.control_methods |= method_names
46
49
 
47
50
  method_names.each do |method_name|
48
- define_method method_name do |*args, &block|
51
+ define_method(method_name) do |*args, &block|
49
52
  control&.send(method_name, *args, &block)
50
53
  end
54
+
55
+ ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
51
56
  end
52
57
  end
53
58
  end
54
59
 
55
-
56
60
  attr_reader :error_handler
57
61
  attr_reader :sticky
58
62
  attr_reader :config_parser
@@ -118,27 +122,25 @@ module Makara
118
122
 
119
123
  def method_missing(m, *args, &block)
120
124
  if METHOD_MISSING_SKIP.include?(m)
121
- return super(m, *args, &block)
125
+ return super
122
126
  end
123
127
 
124
128
  any_connection do |con|
125
- if con.respond_to?(m)
126
- con.public_send(m, *args, &block)
127
- elsif con.respond_to?(m, true)
128
- con.__send__(m, *args, &block)
129
+ if con.respond_to?(m, true)
130
+ con.send(m, *args, &block)
129
131
  else
130
- super(m, *args, &block)
132
+ super
131
133
  end
132
134
  end
133
135
  end
134
136
 
135
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
136
- def respond_to#{RUBY_VERSION.to_s =~ /^1.8/ ? nil : '_missing'}?(m, include_private = false)
137
- any_connection do |con|
138
- con._makara_connection.respond_to?(m, true)
139
- end
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)
140
142
  end
141
- RUBY_EVAL
143
+ end
142
144
 
143
145
  def graceful_connection_for(config)
144
146
  fake_wrapper = Makara::ConnectionWrapper.new(self, nil, config)
@@ -159,15 +161,16 @@ module Makara
159
161
 
160
162
  protected
161
163
 
162
-
163
164
  def send_to_all(method_name, *args)
164
165
  # slave pool must run first to allow for slave-->master failover without running operations on master twice.
165
166
  handling_an_all_execution(method_name) do
166
- @slave_pool.send_to_all method_name, *args
167
- @master_pool.send_to_all method_name, *args
167
+ @slave_pool.send_to_all(method_name, *args)
168
+ @master_pool.send_to_all(method_name, *args)
168
169
  end
169
170
  end
170
171
 
172
+ ruby2_keywords :send_to_all if Module.private_method_defined?(:ruby2_keywords)
173
+
171
174
  def any_connection
172
175
  if @master_pool.disabled
173
176
  @slave_pool.provide do |con|
@@ -202,14 +205,11 @@ module Makara
202
205
  end
203
206
  end
204
207
 
205
-
206
208
  # master or slave
207
209
  def appropriate_pool(method_name, args)
208
-
209
210
  # for testing purposes
210
211
  pool = _appropriate_pool(method_name, args)
211
212
  yield pool
212
-
213
213
  rescue ::Makara::Errors::AllConnectionsBlacklisted, ::Makara::Errors::NoConnectionsAvailable => e
214
214
  if pool == @master_pool
215
215
  @master_pool.connections.each(&:_makara_whitelist!)
@@ -268,7 +268,6 @@ module Makara
268
268
  @hijacked = false
269
269
  end
270
270
 
271
-
272
271
  def stuck_to_master?
273
272
  sticky? && Makara::Context.stuck?(@id)
274
273
  end
@@ -316,16 +315,15 @@ module Makara
316
315
  # this means slave connections are good.
317
316
  return
318
317
  end
318
+
319
319
  @slave_pool.disabled = true
320
320
  yield
321
321
  ensure
322
322
  @slave_pool.disabled = false
323
323
  end
324
324
 
325
-
326
325
  def connection_for(config)
327
326
  Kernel.raise NotImplementedError
328
327
  end
329
-
330
328
  end
331
329
  end
@@ -1,9 +1,7 @@
1
1
  module Makara
2
2
  class Railtie < ::Rails::Railtie
3
-
4
3
  initializer "makara.configure_rails_initialization" do |app|
5
4
  app.middleware.use Makara::Middleware
6
5
  end
7
-
8
6
  end
9
7
  end
@@ -2,6 +2,7 @@ module Makara
2
2
  module Strategies
3
3
  class Abstract
4
4
  attr_reader :pool
5
+
5
6
  def initialize(pool)
6
7
  @pool = pool
7
8
  init
@@ -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
@@ -3,7 +3,6 @@ require 'makara/errors/invalid_shard'
3
3
  module Makara
4
4
  module Strategies
5
5
  class ShardAware < ::Makara::Strategies::Abstract
6
-
7
6
  def init
8
7
  @shards = {}
9
8
  @default_shard = pool.default_shard
@@ -41,7 +40,6 @@ module Makara
41
40
  def shard_id
42
41
  Thread.current['makara_shard_id'] || pool.default_shard
43
42
  end
44
-
45
43
  end
46
44
  end
47
45
  end
@@ -1,15 +1,13 @@
1
1
  module Makara
2
2
  module VERSION
3
-
4
3
  MAJOR = 0
5
4
  MINOR = 5
6
- PATCH = 0
5
+ PATCH = 1
7
6
  PRE = nil
8
7
 
9
8
  def self.to_s
10
9
  [MAJOR, MINOR, PATCH, PRE].compact.join('.')
11
10
  end
12
-
13
11
  end unless defined?(::Makara::VERSION)
14
12
  ::Makara::VERSION
15
13
  end
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,11 +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 = "https://github.com/taskrabbit/makara"
8
+ gem.homepage = "https://github.com/instacart/makara"
10
9
  gem.licenses = ['MIT']
11
10
  gem.metadata = {
12
- "source_code_uri" => 'https://github.com/taskrabbit/makara'
13
- }
11
+ "source_code_uri" => 'https://github.com/instacart/makara'
12
+ }
14
13
 
15
14
  gem.files = `git ls-files`.split($\)
16
15
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -19,5 +18,25 @@ Gem::Specification.new do |gem|
19
18
  gem.require_paths = ["lib"]
20
19
  gem.version = Makara::VERSION
21
20
 
22
- gem.add_dependency 'activerecord', '>= 3.0.0'
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
23
42
  end