makara 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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,32 +1,17 @@
1
1
  require 'active_record/connection_adapters/makara_abstract_adapter'
2
2
  require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
- if ActiveRecord::VERSION::MAJOR >= 4
5
-
6
- module ActiveRecord
7
- module ConnectionHandling
8
- def makara_postgresql_connection(config)
9
- ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter.new(config)
10
- end
11
- end
12
- end
13
-
14
- else
15
-
16
- module ActiveRecord
17
- class Base
18
- def self.makara_postgresql_connection(config)
19
- ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter.new(config)
20
- end
4
+ module ActiveRecord
5
+ module ConnectionHandling
6
+ def makara_postgresql_connection(config)
7
+ ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter.new(config)
21
8
  end
22
9
  end
23
-
24
10
  end
25
11
 
26
12
  module ActiveRecord
27
13
  module ConnectionAdapters
28
14
  class MakaraPostgreSQLAdapter < ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter
29
-
30
15
  class << self
31
16
  def visitor_for(*args)
32
17
  ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.visitor_for(*args)
@@ -38,7 +23,6 @@ module ActiveRecord
38
23
  def active_record_connection_for(config)
39
24
  ::ActiveRecord::Base.postgresql_connection(config)
40
25
  end
41
-
42
26
  end
43
27
  end
44
28
  end
@@ -1,32 +1,17 @@
1
1
  require 'active_record/connection_adapters/makara_abstract_adapter'
2
2
  require 'active_record/connection_adapters/mysql2_adapter'
3
3
 
4
- if ActiveRecord::VERSION::MAJOR >= 4
5
-
6
- module ActiveRecord
7
- module ConnectionHandling
8
- def mysql2_makara_connection(config)
9
- ActiveRecord::ConnectionAdapters::MakaraMysql2Adapter.new(config)
10
- end
11
- end
12
- end
13
-
14
- else
15
-
16
- module ActiveRecord
17
- class Base
18
- def self.mysql2_makara_connection(config)
19
- ActiveRecord::ConnectionAdapters::MakaraMysql2Adapter.new(config)
20
- end
4
+ module ActiveRecord
5
+ module ConnectionHandling
6
+ def mysql2_makara_connection(config)
7
+ ActiveRecord::ConnectionAdapters::MakaraMysql2Adapter.new(config)
21
8
  end
22
9
  end
23
-
24
10
  end
25
11
 
26
12
  module ActiveRecord
27
13
  module ConnectionAdapters
28
14
  class MakaraMysql2Adapter < ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter
29
-
30
15
  class << self
31
16
  def visitor_for(*args)
32
17
  ActiveRecord::ConnectionAdapters::Mysql2Adapter.visitor_for(*args)
@@ -38,7 +23,6 @@ module ActiveRecord
38
23
  def active_record_connection_for(config)
39
24
  ::ActiveRecord::Base.mysql2_connection(config)
40
25
  end
41
-
42
26
  end
43
27
  end
44
28
  end
@@ -1,32 +1,17 @@
1
1
  require 'active_record/connection_adapters/makara_abstract_adapter'
2
2
  require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
- if ActiveRecord::VERSION::MAJOR >= 4
5
-
6
- module ActiveRecord
7
- module ConnectionHandling
8
- def postgresql_makara_connection(config)
9
- ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter.new(config)
10
- end
11
- end
12
- end
13
-
14
- else
15
-
16
- module ActiveRecord
17
- class Base
18
- def self.postgresql_makara_connection(config)
19
- ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter.new(config)
20
- end
4
+ module ActiveRecord
5
+ module ConnectionHandling
6
+ def postgresql_makara_connection(config)
7
+ ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter.new(config)
21
8
  end
22
9
  end
23
-
24
10
  end
25
11
 
26
12
  module ActiveRecord
27
13
  module ConnectionAdapters
28
14
  class MakaraPostgreSQLAdapter < ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter
29
-
30
15
  class << self
31
16
  def visitor_for(*args)
32
17
  ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.visitor_for(*args)
@@ -38,7 +23,6 @@ module ActiveRecord
38
23
  def active_record_connection_for(config)
39
24
  ::ActiveRecord::Base.postgresql_connection(config)
40
25
  end
41
-
42
26
  end
43
27
  end
44
28
  end
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'
@@ -33,7 +32,6 @@ module Makara
33
32
  autoload :PriorityFailover, 'makara/strategies/priority_failover'
34
33
  autoload :ShardAware, 'makara/strategies/shard_aware'
35
34
  end
36
-
37
35
  end
38
36
 
39
37
  ActiveSupport.on_load(:active_record) do
data/lib/makara/cache.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  module Makara
2
2
  module Cache
3
-
4
3
  class << self
5
-
6
4
  def store=(store)
7
5
  Makara::Logging::Logger.log deprecation_warning, :warn
8
6
  end
@@ -20,11 +20,10 @@ require 'cgi'
20
20
 
21
21
  module Makara
22
22
  class ConfigParser
23
-
24
23
  DEFAULTS = {
25
- :master_ttl => 5,
26
- :blacklist_duration => 30,
27
- :sticky => true
24
+ master_ttl: 5,
25
+ blacklist_duration: 30,
26
+ sticky: true
28
27
  }
29
28
 
30
29
  # ConnectionUrlResolver is borrowed from Rails 4-2 since its location and implementation
@@ -33,7 +32,6 @@ module Makara
33
32
  #
34
33
  # Expands a connection string into a hash.
35
34
  class ConnectionUrlResolver # :nodoc:
36
-
37
35
  # == Example
38
36
  #
39
37
  # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
@@ -50,6 +48,7 @@ module Makara
50
48
  # }
51
49
  def initialize(url)
52
50
  raise "Database URL cannot be empty" if url.blank?
51
+
53
52
  @uri = URI.parse(url)
54
53
  @adapter = @uri.scheme.tr('-', '_')
55
54
  @adapter = "postgresql" if @adapter == "postgres"
@@ -131,6 +130,7 @@ module Makara
131
130
  Makara::Logging::Logger.log "Please rename DATABASE_URL to use in the database.yml", :warn
132
131
  end
133
132
  return config unless config.key?(:url)
133
+
134
134
  url = config[:url]
135
135
  url_config = ConnectionUrlResolver.new(url).to_hash
136
136
  url_config = url_config.symbolize_keys
@@ -148,7 +148,6 @@ module Makara
148
148
  @id = sanitize_id(@makara_config[:id])
149
149
  end
150
150
 
151
-
152
151
  def id
153
152
  @id ||= begin
154
153
  sorted = recursive_sort(@config)
@@ -156,24 +155,20 @@ module Makara
156
155
  end
157
156
  end
158
157
 
159
-
160
158
  def master_configs
161
159
  all_configs
162
160
  .select { |config| config[:role] == 'master' }
163
161
  .map { |config| config.except(:role) }
164
162
  end
165
163
 
166
-
167
164
  def slave_configs
168
165
  all_configs
169
166
  .reject { |config| config[:role] == 'master' }
170
167
  .map { |config| config.except(:role) }
171
168
  end
172
169
 
173
-
174
170
  protected
175
171
 
176
-
177
172
  def all_configs
178
173
  @makara_config[:connections].map do |connection|
179
174
  base_config.merge(makara_config.except(:connections))
@@ -181,12 +176,10 @@ module Makara
181
176
  end
182
177
  end
183
178
 
184
-
185
179
  def base_config
186
180
  @base_config ||= DEFAULTS.merge(@config).except(:makara)
187
181
  end
188
182
 
189
-
190
183
  def recursive_sort(thing)
191
184
  return thing.to_s unless thing.include?(Enumerable)
192
185
 
@@ -195,10 +188,8 @@ module Makara
195
188
  end
196
189
 
197
190
  thing.sort_by(&:to_s)
198
-
199
191
  end
200
192
 
201
-
202
193
  def sanitize_id(id)
203
194
  return if id.nil? || id.empty?
204
195
 
@@ -7,7 +7,6 @@ require 'active_support/core_ext/hash/keys'
7
7
 
8
8
  module Makara
9
9
  class ConnectionWrapper
10
-
11
10
  attr_accessor :initial_error, :config
12
11
 
13
12
  # invalid queries caused by connections switching that needs to be replaced
@@ -16,7 +15,7 @@ module Makara
16
15
  def initialize(proxy, connection, config)
17
16
  @config = config.symbolize_keys
18
17
  @connection = connection
19
- @proxy = proxy
18
+ @proxy = proxy
20
19
 
21
20
  if connection.nil?
22
21
  _makara_blacklist!
@@ -45,7 +44,7 @@ module Makara
45
44
  end
46
45
 
47
46
  def _makara_in_transaction?
48
- @connection && @connection.open_transactions > 0 ? true : false
47
+ @connection && @connection.open_transactions > 0
49
48
  end
50
49
 
51
50
  # blacklist this node for @config[:blacklist_duration] seconds
@@ -103,28 +102,21 @@ module Makara
103
102
 
104
103
  # we want to forward all private methods, since we could have kicked out from a private scenario
105
104
  def method_missing(m, *args, &block)
106
- if _makara_connection.respond_to?(m)
107
- _makara_connection.public_send(m, *args, &block)
108
- else # probably private method
109
- _makara_connection.__send__(m, *args, &block)
110
- end
105
+ _makara_connection.send(m, *args, &block)
111
106
  end
112
107
 
108
+ ruby2_keywords :method_missing if Module.private_method_defined?(:ruby2_keywords)
113
109
 
114
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
115
- def respond_to#{RUBY_VERSION.to_s =~ /^1.8/ ? nil : '_missing'}?(m, include_private = false)
116
- _makara_connection.respond_to?(m, true)
117
- end
118
- RUBY_EVAL
119
-
110
+ def respond_to_missing?(m, include_private = false)
111
+ _makara_connection.respond_to?(m, true)
112
+ end
120
113
 
121
114
  protected
122
115
 
123
116
  # once the underlying connection is present we must evaluate extra functionality into it.
124
117
  # all extra functionality is in the format of _makara*
125
118
  def _makara_decorate_connection(con)
126
-
127
- extension = %Q{
119
+ extension = <<~RUBY
128
120
  # the proxy object controlling this connection
129
121
  def _makara
130
122
  @_makara
@@ -148,47 +140,52 @@ module Makara
148
140
  def _makara_name
149
141
  #{@config[:name].inspect}
150
142
  end
151
- }
143
+ RUBY
144
+
145
+ args = RUBY_VERSION >= "3.0.0" ? "..." : "*args, &block"
152
146
 
153
147
  # Each method the Makara::Proxy needs to hijack should be redefined in the underlying connection.
154
148
  # The new definition should allow for the proxy to intercept the invocation if required.
155
149
  @proxy.class.hijack_methods.each do |meth|
156
- extension << %Q{
157
- def #{meth}(*args, &block)
150
+ method_call = RUBY_VERSION >= "3.0.0" ? "public_send(#{meth.inspect}, ...)" : "#{meth}(*args, &block)"
151
+
152
+ extension << <<~RUBY
153
+ def #{meth}(#{args})
158
154
  _makara_hijack do |proxy|
159
155
  if proxy
160
- proxy.#{meth}(*args, &block)
156
+ proxy.#{method_call}
161
157
  else
162
158
  super
163
159
  end
164
160
  end
165
161
  end
166
- }
162
+ RUBY
167
163
  end
168
164
 
169
165
  # Control methods must always be passed to the
170
166
  # Makara::Proxy control object for handling (typically
171
167
  # related to ActiveRecord connection pool management)
172
168
  @proxy.class.control_methods.each do |meth|
173
- extension << %Q{
174
- def #{meth}(*args, &block)
169
+ method_call = RUBY_VERSION >= "3.0.0" ? "public_send(#{meth.inspect}, ...)" : "#{meth}(*args=args, block)"
170
+
171
+ extension << <<~RUBY
172
+ def #{meth}(#{args})
175
173
  proxy = _makara
176
174
  if proxy
177
- proxy.control.#{meth}(*args=args, block)
175
+ proxy.control.#{method_call}
178
176
  else
179
177
  super # Only if we are not wrapped any longer
180
178
  end
181
179
  end
182
- }
180
+ RUBY
183
181
  end
184
182
 
185
183
  # extend the instance
186
- con.instance_eval(extension)
184
+ con.instance_eval(extension, __FILE__, __LINE__ + 1)
187
185
  # set the makara context
188
186
  con._makara = @proxy
189
187
 
190
188
  con._makara
191
189
  end
192
-
193
190
  end
194
191
  end
@@ -123,6 +123,7 @@ module Makara
123
123
  end
124
124
 
125
125
  protected
126
+
126
127
  def current
127
128
  fetch(:makara_current_context) { new({}) }
128
129
  end
data/lib/makara/cookie.rb CHANGED
@@ -22,6 +22,7 @@ module Makara
22
22
  end
23
23
 
24
24
  private
25
+
25
26
  # Pairs of {proxy_id}:{timestamp}, separated by "|"
26
27
  # proxy_id1:1518270031.3132212|proxy_id2:1518270030.313232 ..
27
28
  def parse(cookie_string)
@@ -4,36 +4,27 @@
4
4
 
5
5
  module Makara
6
6
  class ErrorHandler
7
-
8
-
9
7
  def handle(connection)
10
8
  yield
11
-
12
9
  rescue Exception => e
13
-
14
10
  if e.is_a?(Makara::Errors::MakaraError)
15
11
  harshly(e)
16
12
  else
17
13
  gracefully(connection, e)
18
14
  end
19
-
20
15
  end
21
16
 
22
-
23
17
  protected
24
18
 
25
-
26
19
  def gracefully(connection, e)
27
20
  err = Makara::Errors::BlacklistConnection.new(connection, e)
28
21
  ::Makara::Logging::Logger.log("Gracefully handling: #{err}")
29
22
  raise err
30
23
  end
31
24
 
32
-
33
25
  def harshly(e)
34
26
  ::Makara::Logging::Logger.log("Harshly handling: #{e}\n#{e.backtrace.join("\n\t")}")
35
27
  raise e
36
28
  end
37
-
38
29
  end
39
30
  end
@@ -1,13 +1,11 @@
1
1
  module Makara
2
2
  module Errors
3
3
  class AllConnectionsBlacklisted < MakaraError
4
-
5
4
  def initialize(pool, errors)
6
5
  errors = [*errors]
7
6
  messages = errors.empty? ? 'No error details' : errors.map(&:message).join(' -> ')
8
7
  super "[Makara/#{pool.role}] All connections are blacklisted -> " + messages
9
8
  end
10
-
11
9
  end
12
10
  end
13
11
  end