replica_pools 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9a32096014e9f2cd137adb7c8fe226173f40d9dea893a319c0dab24cbdf8371
4
- data.tar.gz: da62952df8213322963f8b8ce0c5da9ed8efe381c2348801794ec0ef0b6d294a
3
+ metadata.gz: 9d9219fb04b0b4118f99202ad78486d565bb88fe57079f743336b381b50d5864
4
+ data.tar.gz: e3fefd1456ce775cf127e0561d5827b39d4a45fab0ef4359178bf58d841887bc
5
5
  SHA512:
6
- metadata.gz: 7f2d2abc5f7badb102c8116213b306d35336f6d54c651a74d6fcaa0e37c53c5282c46fbc643984ffde43f5e54d868051c38590372b8af4329741da1247b68128
7
- data.tar.gz: 51c4514ec6e0fa79ea2e6b128fd4d6d3866916d65d89ec743f49621678a5997c0dd3bc0bfe78a25acd72c39d61c5f13523a9f84a9160259966f9408f9c56b109
6
+ metadata.gz: a1777856dd70f4fd661ef3a7ca6d149f57772e72e9636cd0ef674476c858fa8ce1e086a846a79e624924c1838765e39a88273fb0d3d6b01812c01be7668fe69c
7
+ data.tar.gz: 0f6f739901cfcf978c9d6b0b1a4e9efbd46c66c33954ab577186343c74eb5a9e499c15ed2d8fa6d8c97afc1f85854e81ef72cbeced472cc5cd0d7f0db59e3e15
data/README.md CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  Easy Single Leader / Multiple Replica Setup for use in Ruby/Rails projects
4
4
 
5
- [![Build
6
- Status](https://travis-ci.org/kickstarter/replica_pools.png?branch=owningit)](https://travis-ci.org/kickstarter/replica_pools)
5
+ [![Spec](https://github.com/kickstarter/replica_pools/actions/workflows/spec.yml/badge.svg)](https://github.com/kickstarter/replica_pools/actions/workflows/spec.yml)
7
6
 
8
7
  ## Overview
9
8
 
@@ -11,22 +10,22 @@ ReplicaPools replaces ActiveRecord's connection with a proxy that routes databas
11
10
 
12
11
  ReplicaPools also provides helpers so you can customize your replica strategy. You can organize replicas into pools and cycle through them (e.g. in a before_filter). You can make the connection default to the leader, or the default replica pool, and then use block helpers to temporarily change the behavior (e.g. in an around_filter).
13
12
 
14
- * Uses a naming convention in database.yml to designate replica pools.
15
- * Defaults to a given replica pool, but may also be configured to default to leader.
16
- * Routes database interactions (queries) to the right connection
17
- * Whitelisted queries go to the current connection (might be a replica).
18
- * All queries inside a transaction run on leader.
19
- * All other queries are also sent to the leader connection.
20
- * Supports ActiveRecord's in-memory query caching.
21
- * Helper methods can be used to easily load balance replicas, route traffic to different replica pools, or run directly against leader. (examples below)
13
+ - Uses a naming convention in database.yml to designate replica pools.
14
+ - Defaults to a given replica pool, but may also be configured to default to leader.
15
+ - Routes database interactions (queries) to the right connection
16
+ - Whitelisted queries go to the current connection (might be a replica).
17
+ - All queries inside a transaction run on leader.
18
+ - All other queries are also sent to the leader connection.
19
+ - Supports ActiveRecord's in-memory query caching.
20
+ - Helper methods can be used to easily load balance replicas, route traffic to different replica pools, or run directly against leader. (examples below)
22
21
 
23
22
  ## Not Supported
24
23
 
25
- * Sharding.
26
- * Automatic load balancing strategies.
27
- * Replica weights. You can accomplish this in your own load balancing strategy.
28
- * Whitelisting models that always use leader.
29
- * Blacklisting poorly performing replicas. This could cause load spikes on your leader. Whatever provisions your database.yml should make this choice.
24
+ - Sharding.
25
+ - Automatic load balancing strategies.
26
+ - Replica weights. You can accomplish this in your own load balancing strategy.
27
+ - Whitelisting models that always use leader.
28
+ - Blacklisting poorly performing replicas. This could cause load spikes on your leader. Whatever provisions your database.yml should make this choice.
30
29
 
31
30
  ## Installation and Setup
32
31
 
@@ -166,7 +165,7 @@ To disable queries to the leader database -- for instance, in a production
166
165
  console -- set the disable_leader configuration to false. This will raise
167
166
  a ReplicaPools::LeaderDisabled error:
168
167
 
169
- ReplicaPools.config.disable_leader = false
168
+ ReplicaPools.config.disable_leader = false
170
169
 
171
170
  ## Running specs
172
171
 
@@ -204,10 +203,10 @@ Released under the MIT license
204
203
 
205
204
  The project is based on:
206
205
 
207
- * https://github.com/schoefmax/multi_db
206
+ - https://github.com/schoefmax/multi_db
208
207
 
209
208
  ### Masochism
210
209
 
211
210
  The original leader/replica plugin:
212
211
 
213
- * http://github.com/technoweenie/masochism
212
+ - http://github.com/technoweenie/masochism
@@ -11,26 +11,18 @@ module ReplicaPools
11
11
  class << self
12
12
  def generate_safe_delegations
13
13
  ReplicaPools.config.safe_methods.each do |method|
14
- generate_safe_delegation(method) unless instance_methods.include?(method)
14
+ self.define_method(method) do |*args, &block|
15
+ route_to(current, method, *args, &block)
16
+ end unless instance_methods.include?(method)
15
17
  end
16
18
  end
17
-
18
- protected
19
-
20
- def generate_safe_delegation(method)
21
- class_eval <<-END, __FILE__, __LINE__ + 1
22
- def #{method}(*args, &block)
23
- route_to(current, :#{method}, *args, &block)
24
- end
25
- END
26
- end
27
19
  end
28
20
 
29
21
  def initialize(leader, pools)
30
- @leader = leader
31
- @replica_pools = pools
32
- @leader_depth = 0
33
- @current_pool = default_pool
22
+ @leader = leader
23
+ @replica_pools = pools
24
+ @leader_depth = 0
25
+ @current_pool = default_pool
34
26
 
35
27
  if ReplicaPools.config.defaults_to_leader
36
28
  @current = leader
@@ -91,7 +83,13 @@ module ReplicaPools
91
83
  # Safe methods have been generated during `setup!`.
92
84
  # Creates a method to speed up subsequent calls.
93
85
  def method_missing(method, *args, &block)
94
- generate_unsafe_delegation(method)
86
+ self.class.define_method(method) do |*args, &block|
87
+ route_to(leader, method, *args, &block).tap do
88
+ if %i[insert delete update].include?(method)
89
+ leader.retrieve_connection.clear_query_cache
90
+ end
91
+ end
92
+ end
95
93
  send(method, *args, &block)
96
94
  end
97
95
 
@@ -99,14 +97,6 @@ module ReplicaPools
99
97
  leader_depth > 0
100
98
  end
101
99
 
102
- def generate_unsafe_delegation(method)
103
- self.class_eval <<-END, __FILE__, __LINE__ + 1
104
- def #{method}(*args, &block)
105
- route_to(leader, :#{method}, *args, &block)
106
- end
107
- END
108
- end
109
-
110
100
  def route_to(conn, method, *args, &block)
111
101
  raise ReplicaPools::LeaderDisabled.new if ReplicaPools.config.disable_leader && conn == leader
112
102
  conn.retrieve_connection.send(method, *args, &block)
@@ -10,26 +10,70 @@ module ReplicaPools
10
10
 
11
11
  ReplicaPools.config.safe_methods =
12
12
  if ActiveRecord::VERSION::MAJOR == 3
13
- [
14
- :select_all, :select_one, :select_value, :select_values,
15
- :select_rows, :select, :verify!, :raw_connection, :active?, :reconnect!,
16
- :disconnect!, :reset_runtime, :log, :log_info
13
+ %i[
14
+ active?
15
+ disconnect!
16
+ log
17
+ log_info
18
+ raw_connection
19
+ reconnect!
20
+ reset_runtime
21
+ select
22
+ select_all
23
+ select_one
24
+ select_rows
25
+ select_value
26
+ select_values
27
+ verify!
17
28
  ]
18
29
  elsif ActiveRecord::VERSION::MAJOR == 4
19
- [
20
- :select_all, :select_one, :select_value, :select_values,
21
- :select_rows, :select, :verify!, :raw_connection, :active?, :reconnect!,
22
- :disconnect!, :reset_runtime, :log
30
+ %i[
31
+ active?
32
+ disconnect!
33
+ log
34
+ raw_connection
35
+ reconnect!
36
+ reset_runtime
37
+ select
38
+ select_all
39
+ select_one
40
+ select_rows
41
+ select_value
42
+ select_values
43
+ verify!
23
44
  ]
24
45
  elsif [5, 6].include?(ActiveRecord::VERSION::MAJOR)
25
- [
26
- :select_all, :select_one, :select_value, :select_values,
27
- :select_rows, :select, :select_prepared, :verify!, :raw_connection,
28
- :active?, :reconnect!, :disconnect!, :reset_runtime, :log,
29
- :lookup_cast_type_from_column, :sanitize_limit,
30
- :combine_bind_parameters, :quote_table_name, :quote, :quote_column_names, :quote_table_names, :table_alias_for,
31
- :case_sensitive_comparison, :case_insensitive_comparison,
32
- :schema_cache, :cacheable_query, :prepared_statements, :clear_cache!, :column_name_for_operation
46
+ %i[
47
+ active?
48
+ cacheable_query
49
+ case_insensitive_comparison
50
+ case_sensitive_comparison
51
+ clear_cache!
52
+ column_name_for_operation
53
+ column_name_with_order_matcher
54
+ combine_bind_parameters
55
+ disconnect!
56
+ log
57
+ lookup_cast_type_from_column
58
+ prepared_statements
59
+ quote
60
+ quote_column_names
61
+ quote_table_name
62
+ quote_table_names
63
+ raw_connection
64
+ reconnect!
65
+ reset_runtime
66
+ sanitize_limit
67
+ schema_cache
68
+ select
69
+ select_all
70
+ select_one
71
+ select_prepared
72
+ select_rows
73
+ select_value
74
+ select_values
75
+ table_alias_for
76
+ verify!
33
77
  ]
34
78
  else
35
79
  warn "Unsupported ActiveRecord version #{ActiveRecord.version}. Please whitelist the safe methods."
@@ -6,12 +6,12 @@ module ReplicaPools
6
6
 
7
7
  def initialize
8
8
  pools = {}
9
- pool_configurations.group_by{|_, name, _| name }.each do |name, set|
9
+ pool_configurations.group_by{ |_, name, _| name }.each do |name, set|
10
10
  pools[name.to_sym] = ReplicaPools::Pool.new(
11
11
  name,
12
- set.map{ |conn_name, _, replica_name|
12
+ set.map do |conn_name, _, replica_name|
13
13
  connection_class(name, replica_name, conn_name)
14
- }
14
+ end
15
15
  )
16
16
  end
17
17
 
@@ -47,16 +47,16 @@ module ReplicaPools
47
47
  def connection_class(pool_name, replica_name, connection_name)
48
48
  class_name = "#{pool_name.camelize}#{replica_name.camelize}"
49
49
 
50
- ReplicaPools.module_eval %Q{
51
- class #{class_name} < ActiveRecord::Base
52
- self.abstract_class = true
53
- establish_connection :#{connection_name}
54
- def self.connection_config
55
- configurations[#{connection_name.to_s.inspect}]
56
- end
50
+ ReplicaPools.const_set(class_name, Class.new(ActiveRecord::Base) do |c|
51
+ c.abstract_class = true
52
+ c.define_singleton_method(:connection_config) do
53
+ configurations[connection_name.to_s]
57
54
  end
58
- }, __FILE__, __LINE__
59
- ReplicaPools.const_get(class_name)
55
+ end)
56
+
57
+ ReplicaPools.const_get(class_name).tap do |c|
58
+ c.establish_connection(connection_name.to_sym)
59
+ end
60
60
  end
61
61
  end
62
62
  end
@@ -10,11 +10,9 @@ module ReplicaPools
10
10
 
11
11
  # these methods can all use the leader connection
12
12
  (query_cache_methods - [:select_all]).each do |method_name|
13
- module_eval <<-END, __FILE__, __LINE__ + 1
14
- def #{method_name}(*a, &b)
15
- ActiveRecord::Base.connection.#{method_name}(*a, &b)
16
- end
17
- END
13
+ define_method(method_name) do |*args, &block|
14
+ ActiveRecord::Base.connection.send(method_name, *args, &block)
15
+ end
18
16
  end
19
17
 
20
18
  # select_all is trickier. it needs to use the leader
@@ -1,3 +1,3 @@
1
1
  module ReplicaPools
2
- VERSION = "2.2.1"
2
+ VERSION = "2.3.0"
3
3
  end
data/lib/replica_pools.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'logger'
2
+
1
3
  require 'active_record'
2
4
  require 'replica_pools/config'
3
5
  require 'replica_pools/pool'
@@ -64,7 +66,7 @@ module ReplicaPools
64
66
  end
65
67
 
66
68
  def logger
67
- ActiveRecord::Base.logger
69
+ ActiveRecord::Base.logger || Logger.new(STDOUT)
68
70
  end
69
71
  end
70
72
  end
metadata CHANGED
@@ -1,44 +1,44 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: replica_pools
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Drabik
8
8
  - Lance Ivy
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-04-16 00:00:00.000000000 Z
12
+ date: 2022-04-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 3.2.12
20
+ version: '6.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: 3.2.12
27
+ version: '6.0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: mysql2
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 0.4.4
34
+ version: '0.5'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 0.4.4
41
+ version: '0.5'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rack
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -137,7 +137,7 @@ homepage: https://github.com/kickstarter/replica_pools
137
137
  licenses:
138
138
  - MIT
139
139
  metadata: {}
140
- post_install_message:
140
+ post_install_message:
141
141
  rdoc_options: []
142
142
  require_paths:
143
143
  - lib
@@ -152,8 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
152
  - !ruby/object:Gem::Version
153
153
  version: '1.2'
154
154
  requirements: []
155
- rubygems_version: 3.0.3
156
- signing_key:
155
+ rubygems_version: 3.1.6
156
+ signing_key:
157
157
  specification_version: 4
158
158
  summary: Connection proxy for ActiveRecord for leader / replica setups.
159
159
  test_files: