active_record_host_pool 2.1.0 → 4.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ba0aa0ff3c0b19e4895118e76f84cc57f46481baa482c59925946ecd56765bb
4
- data.tar.gz: e276dbda95168a03b511a5d7da14f94411ca7b8bc910ea2684631f25c9a22cf1
3
+ metadata.gz: 1b17ac5ef20d2f62f857a6a4a7d62ff801767e00c1d5e72b0ec05c9c9818c004
4
+ data.tar.gz: a7a6b9847c9fda19f32c0929f1a99a5362c22193b550b45602d9d8dde7efde27
5
5
  SHA512:
6
- metadata.gz: 5b455f5fd116f96035fa816b39e0baf7f698d885decece79fd213c690c07db6b2f54e2328d4fa8dab68c536e86b58a9261b3c1a4c8aa45ccf35c1cb7b237168e
7
- data.tar.gz: aa7295a9be8e2892ff34452de014ea7627255d58e6eccd6a0d4a18d3b03152adb18fb2e453df017a058eeaf26bf8d4a768db3e436cef7da498f69e03d5f50917
6
+ metadata.gz: 4d9acc6b59e50dcbeea61b75ed8f3428487ce287136c0cc95b314eb871bfff39ff7380abd779e07870d8388d775864e13d4c3b56dd91be3723904a35618c5afa
7
+ data.tar.gz: 96e926441b4e9c70fe7ffbe2f46d76eb8ab729438fa01e967eabcfe043073c928c18c3984d51cb644d6bbcef99fd6cc0d57e23af671fda2fea4665acfdbe4a94
data/Changelog.md CHANGED
@@ -6,6 +6,57 @@ and as of v1.0.0 this project adheres to [Semantic Versioning](https://semver.or
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [4.1.0]
10
+
11
+ ### Changed
12
+ - Remove dependency on `mutex_m`, instead using `Thread::Mutex` directly.
13
+
14
+ ## [4.0.0]
15
+
16
+ ### Changed
17
+ - Moved `select_db` inside of the `with_raw_connection` block of the `#raw_execute` method. This should allow for using Rails' built-in reconnect & retry logic with the Trilogy adapter or Rails 7.1+.
18
+ - In Rails 7.1+, when a new ConnectionProxy is instantiated the database switch is lazily triggered by the subsequent database query instead of immediately.
19
+
20
+ ### Removed
21
+ - Calling `#clean!` and `#verified!` on connections because it is no longer necessary.
22
+
23
+ ## [3.2.0]
24
+
25
+ ### Added
26
+ - Calls `#verified!` on the connection after `#clean!`.
27
+
28
+ ## [3.1.1]
29
+
30
+ ### Fixed
31
+ - A typo causing `#clean!` to not run.
32
+
33
+ ## [3.1.0]
34
+
35
+ ### Added
36
+ - Calls `#clean!` on the connection after switching databases.
37
+
38
+ ## [3.0.0]
39
+
40
+ ### Added
41
+ - Support and testing for Rails 7.2 & Rails main.
42
+
43
+ ### Removed
44
+ - Support for ActiveRecord's legacy connection handling.
45
+
46
+ ## [2.2.0]
47
+
48
+ ### Removed
49
+ - Support for Ruby 3.0.
50
+
51
+ ### Added
52
+ - Rails 6.1 testing with Trilogy.
53
+
54
+ ### Fixed
55
+ - Fixed using ActiveRecordHostPool and the `activerecord-trilogy-adapter v3.1+`.
56
+
57
+ ### Changed
58
+ - ActiveRecordHostPool will now raise an exception if you try to use a version of `activerecord-trilogy-adapter < 3.1`.
59
+
9
60
  ## [2.1.0]
10
61
 
11
62
  ### Changed
@@ -7,9 +7,8 @@ when :trilogy
7
7
  case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
8
8
  when "6.1", "7.0"
9
9
  require "trilogy_adapter/connection"
10
- require "trilogy_adapter/errors"
11
10
  ActiveRecord::Base.extend(TrilogyAdapter::Connection)
12
- when "7.1"
11
+ when "7.1", "7.2", "8.0", "8.1"
13
12
  require "active_record/connection_adapters/trilogy_adapter"
14
13
  else
15
14
  raise "Unsupported version of Rails (v#{ActiveRecord::VERSION::STRING})"
@@ -18,31 +17,34 @@ end
18
17
 
19
18
  module ActiveRecordHostPool
20
19
  module DatabaseSwitch
21
- attr_reader :_host_pool_current_database
20
+ attr_reader :_host_pool_desired_database
22
21
  def initialize(*)
23
22
  @_cached_current_database = nil
24
23
  super
25
24
  end
26
25
 
27
- def _host_pool_current_database=(database)
28
- @_host_pool_current_database = database
29
- @config[:database] = _host_pool_current_database
26
+ def _host_pool_desired_database=(database)
27
+ @_host_pool_desired_database = database
28
+ @config[:database] = _host_pool_desired_database
30
29
  end
31
30
 
32
31
  if ActiveRecord.version >= Gem::Version.new("7.1")
33
- # Patch `raw_execute` instead of `execute` since this commit:
34
- # https://github.com/rails/rails/commit/f69bbcbc0752ca5d5af327d55922614a26f5c7e9
35
- def raw_execute(...)
36
- if _host_pool_current_database && !_no_switch
37
- _switch_connection
32
+ def with_raw_connection(...)
33
+ super do |real_connection|
34
+ _switch_connection(real_connection) if _host_pool_desired_database && !_no_switch
35
+ yield real_connection
36
+ end
37
+ end
38
+ elsif ActiveRecordHostPool.loaded_db_adapter == :trilogy
39
+ def with_trilogy_connection(...)
40
+ super do |real_connection|
41
+ _switch_connection(real_connection) if _host_pool_desired_database && !_no_switch
42
+ yield real_connection
38
43
  end
39
- super
40
44
  end
41
45
  else
42
46
  def execute(...)
43
- if _host_pool_current_database && !_no_switch
44
- _switch_connection
45
- end
47
+ _switch_connection(raw_connection) if _host_pool_desired_database && !_no_switch
46
48
  super
47
49
  end
48
50
  end
@@ -71,31 +73,50 @@ module ActiveRecordHostPool
71
73
 
72
74
  attr_accessor :_no_switch
73
75
 
74
- def _switch_connection
75
- if _host_pool_current_database &&
76
+ def _switch_connection(real_connection)
77
+ if _host_pool_desired_database &&
76
78
  (
77
- (_host_pool_current_database != @_cached_current_database) ||
78
- @connection.object_id != @_cached_connection_object_id
79
- )
80
- log("select_db #{_host_pool_current_database}", "SQL") do
79
+ _desired_database_changed? ||
80
+ _real_connection_changed?
81
+ )
82
+ log("select_db #{_host_pool_desired_database}", "SQL") do
81
83
  clear_cache!
82
- raw_connection.select_db(_host_pool_current_database)
84
+ real_connection.select_db(_host_pool_desired_database)
83
85
  end
84
- @_cached_current_database = _host_pool_current_database
85
- @_cached_connection_object_id = @connection.object_id
86
+ @_cached_current_database = _host_pool_desired_database
87
+ @_cached_connection_object_id = _real_connection_object_id
88
+ end
89
+ end
90
+
91
+ def _desired_database_changed?
92
+ _host_pool_desired_database != @_cached_current_database
93
+ end
94
+
95
+ # rubocop:disable Lint/DuplicateMethods
96
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
97
+ when "6.1", "7.0", "7.1"
98
+ def _real_connection_object_id
99
+ @connection.object_id
100
+ end
101
+ else
102
+ def _real_connection_object_id
103
+ @raw_connection.object_id
86
104
  end
87
105
  end
106
+ # rubocop:enable Lint/DuplicateMethods
107
+
108
+ def _real_connection_changed?
109
+ _real_connection_object_id != @_cached_connection_object_id
110
+ end
88
111
 
89
112
  # prevent different databases from sharing the same query cache
90
113
  def cache_sql(sql, *args)
91
- super(_host_pool_current_database.to_s + "/" + sql, *args)
114
+ super(_host_pool_desired_database.to_s + "/" + sql, *args)
92
115
  end
93
116
  end
94
117
 
95
118
  module PoolConfigPatch
96
119
  def pool
97
- ActiveSupport::ForkTracker.check!
98
-
99
120
  @pool || synchronize { @pool ||= ActiveRecordHostPool::PoolProxy.new(self) }
100
121
  end
101
122
  end
@@ -14,7 +14,7 @@ module ActiveRecordHostPool
14
14
  end
15
15
 
16
16
  def __getobj__
17
- @cx._host_pool_current_database = @database
17
+ @cx._host_pool_desired_database = @database
18
18
  @cx
19
19
  end
20
20
 
@@ -3,7 +3,6 @@
3
3
  require "delegate"
4
4
  require "active_record"
5
5
  require "active_record_host_pool/connection_adapter_mixin"
6
- require "mutex_m"
7
6
 
8
7
  # this module sits in between ConnectionHandler and a bunch of different ConnectionPools (one per host).
9
8
  # when a connection is requested, it goes like:
@@ -16,8 +15,6 @@ require "mutex_m"
16
15
  module ActiveRecordHostPool
17
16
  # Sits between ConnectionHandler and a bunch of different ConnectionPools (one per host).
18
17
  class PoolProxy < Delegator
19
- include Mutex_m
20
-
21
18
  case ActiveRecordHostPool.loaded_db_adapter
22
19
  when :mysql2
23
20
  RESCUABLE_DB_ERROR = Mysql2::Error
@@ -26,9 +23,10 @@ module ActiveRecordHostPool
26
23
  end
27
24
 
28
25
  def initialize(pool_config)
29
- super(pool_config)
26
+ super
30
27
  @pool_config = pool_config
31
28
  @config = pool_config.db_config.configuration_hash
29
+ @mutex = Mutex.new
32
30
  end
33
31
 
34
32
  def __getobj__
@@ -43,17 +41,35 @@ module ActiveRecordHostPool
43
41
 
44
42
  attr_reader :pool_config
45
43
 
46
- def connection(*args)
47
- real_connection = _unproxied_connection(*args)
48
- _connection_proxy_for(real_connection, @config[:database])
49
- rescue RESCUABLE_DB_ERROR, ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid
50
- _connection_pools.delete(_pool_key)
51
- Kernel.raise
52
- end
44
+ # rubocop:disable Lint/DuplicateMethods
45
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
46
+ when "6.1", "7.0", "7.1"
47
+ def connection(*args)
48
+ real_connection = _unproxied_connection(*args)
49
+ _connection_proxy_for(real_connection, @config[:database])
50
+ rescue RESCUABLE_DB_ERROR, ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid
51
+ _connection_pools.delete(_pool_key)
52
+ Kernel.raise
53
+ end
53
54
 
54
- def _unproxied_connection(*args)
55
- _connection_pool.connection(*args)
55
+ def _unproxied_connection(*args)
56
+ _connection_pool.connection(*args)
57
+ end
58
+ else
59
+ def lease_connection(*args)
60
+ real_connection = _unproxied_connection(*args)
61
+ _connection_proxy_for(real_connection, @config[:database])
62
+ rescue RESCUABLE_DB_ERROR, ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid
63
+ _connection_pools.delete(_pool_key)
64
+ Kernel.raise
65
+ end
66
+ alias_method :connection, :lease_connection
67
+
68
+ def _unproxied_connection(*args)
69
+ _connection_pool.lease_connection(*args)
70
+ end
56
71
  end
72
+ # rubocop:enable Lint/DuplicateMethods
57
73
 
58
74
  # by the time we are patched into ActiveRecord, the current thread has already established
59
75
  # a connection. thus we need to patch both connection and checkout/checkin
@@ -67,18 +83,55 @@ module ActiveRecordHostPool
67
83
  _connection_pool.checkin(cx)
68
84
  end
69
85
 
70
- def with_connection
71
- cx = checkout
72
- yield cx
73
- ensure
74
- checkin cx
86
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
87
+ when "6.1", "7.0", "7.1"
88
+ def with_connection
89
+ cx = checkout
90
+ yield cx
91
+ ensure
92
+ checkin cx
93
+ end
94
+ else
95
+ def with_connection(prevent_permanent_checkout: false) # rubocop:disable Lint/DuplicateMethods
96
+ real_connection_lease = _connection_pool.send(:connection_lease)
97
+ sticky_was = real_connection_lease.sticky
98
+ real_connection_lease.sticky = false if prevent_permanent_checkout
99
+
100
+ if real_connection_lease.connection
101
+ begin
102
+ yield _connection_proxy_for(real_connection_lease.connection, @config[:database])
103
+ ensure
104
+ real_connection_lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was
105
+ end
106
+ else
107
+ begin
108
+ real_connection_lease.connection = _unproxied_connection
109
+ yield _connection_proxy_for(real_connection_lease.connection, @config[:database])
110
+ ensure
111
+ real_connection_lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was
112
+ _connection_pool.release_connection(real_connection_lease) unless real_connection_lease.sticky
113
+ end
114
+ end
115
+ end
116
+
117
+ def active_connection?
118
+ real_connection_lease = _connection_pool.send(:connection_lease)
119
+ if real_connection_lease.connection
120
+ _connection_proxy_for(real_connection_lease.connection, @config[:database])
121
+ end
122
+ end
123
+ alias_method :active_connection, :active_connection?
124
+
125
+ def schema_cache
126
+ @schema_cache ||= ActiveRecord::ConnectionAdapters::BoundSchemaReflection.new(_connection_pool.schema_reflection, self)
127
+ end
75
128
  end
76
129
 
77
130
  def disconnect!
78
131
  p = _connection_pool(false)
79
132
  return unless p
80
133
 
81
- synchronize do
134
+ @mutex.synchronize do
82
135
  p.disconnect!
83
136
  p.automatic_reconnect = true
84
137
  _clear_connection_proxy_cache
@@ -164,12 +217,7 @@ module ActiveRecordHostPool
164
217
  @connection_proxy_cache ||= {}
165
218
  key = [connection, database]
166
219
 
167
- @connection_proxy_cache[key] ||= begin
168
- cx = ActiveRecordHostPool::ConnectionProxy.new(connection, database)
169
- cx.raw_execute("SELECT 1", "ARHP SWITCH DB")
170
-
171
- cx
172
- end
220
+ @connection_proxy_cache[key] ||= ActiveRecordHostPool::ConnectionProxy.new(connection, database)
173
221
  end
174
222
  end
175
223
  # standard:enable Lint/DuplicateMethods
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordHostPool
4
- VERSION = "2.1.0"
4
+ VERSION = "4.1.0"
5
5
  end
@@ -15,7 +15,11 @@ if Gem.loaded_specs.include?("mysql2")
15
15
  ActiveRecordHostPool.loaded_db_adapter = :mysql2
16
16
  elsif Gem.loaded_specs.include?("trilogy")
17
17
  require "trilogy"
18
- require "activerecord-trilogy-adapter" if ActiveRecord.version < Gem::Version.new("7.1")
18
+ if ActiveRecord.version < Gem::Version.new("7.1")
19
+ require "activerecord-trilogy-adapter"
20
+ require "trilogy_adapter/version"
21
+ raise "ActiveRecordHostPool is only compatible with activerecord-trilogy-adapter v3.1+" if Gem::Version.new("3.1") > TrilogyAdapter::VERSION
22
+ end
19
23
  ActiveRecordHostPool.loaded_db_adapter = :trilogy
20
24
  end
21
25
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_host_pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Quorning
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2024-04-19 00:00:00.000000000 Z
14
+ date: 2024-12-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activerecord
@@ -20,9 +20,6 @@ dependencies:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
22
  version: 6.1.0
23
- - - "<"
24
- - !ruby/object:Gem::Version
25
- version: '7.2'
26
23
  type: :runtime
27
24
  prerelease: false
28
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,9 +27,6 @@ dependencies:
30
27
  - - ">="
31
28
  - !ruby/object:Gem::Version
32
29
  version: 6.1.0
33
- - - "<"
34
- - !ruby/object:Gem::Version
35
- version: '7.2'
36
30
  description: ''
37
31
  email:
38
32
  - bquorning@zendesk.com
@@ -65,14 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
65
59
  requirements:
66
60
  - - ">="
67
61
  - !ruby/object:Gem::Version
68
- version: 3.0.0
62
+ version: 3.1.0
69
63
  required_rubygems_version: !ruby/object:Gem::Requirement
70
64
  requirements:
71
65
  - - ">="
72
66
  - !ruby/object:Gem::Version
73
67
  version: '0'
74
68
  requirements: []
75
- rubygems_version: 3.5.3
69
+ rubygems_version: 3.5.22
76
70
  signing_key:
77
71
  specification_version: 4
78
72
  summary: Allow ActiveRecord to share a connection to multiple databases on the same