active_record_host_pool 4.2.0 → 4.3.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 +4 -4
- data/Changelog.md +12 -0
- data/Readme.md +3 -7
- data/lib/active_record_host_pool/connection_adapter_mixin.rb +13 -12
- data/lib/active_record_host_pool/connection_proxy.rb +10 -5
- data/lib/active_record_host_pool/pool_proxy.rb +37 -64
- data/lib/active_record_host_pool/version.rb +1 -1
- data/lib/active_record_host_pool.rb +0 -1
- metadata +4 -5
- data/lib/active_record_host_pool/clear_query_cache_patch.rb +0 -34
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fced473565b601f6ec0a0e682b254c251d653c10be16690c46470d418dd9f346
|
|
4
|
+
data.tar.gz: 7281ce45c44d5209f16444e55caaaf4c2a059981d6a41a48d45d0f394c08b4a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a053ec7e487686f9ab3aa0b5c01912292aee086f3d9e2444e715c99f9ef278c564b2a48b8eceb68030972c10ac20c04b20745689e88efdd9ae333256a033a371
|
|
7
|
+
data.tar.gz: d6f6bc52d1e46987faf4b7d57b7e6df43464e60ed978b3337056957f3e8d5b98ed1fc38f156ea1766b7c299ee1094a68e3ec6a13e8741117e311cb23d54ce385
|
data/Changelog.md
CHANGED
|
@@ -6,6 +6,18 @@ and as of v1.0.0 this project adheres to [Semantic Versioning](https://semver.or
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [4.3.0]
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- `.class_eval` now raises an exception when called on `ConnectionProxy`. Use `.arhp_connection_proxy_class_eval` if you _really_ need to modify the `ConnectionProxy` class.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Testing with Rails 8.1.
|
|
16
|
+
|
|
17
|
+
### Removed
|
|
18
|
+
- `ConnectionProxy` no longer overrides `#class` to return the class of the proxied connection adapter.
|
|
19
|
+
- Support for Rails 7.1.
|
|
20
|
+
|
|
9
21
|
## [4.2.0]
|
|
10
22
|
|
|
11
23
|
### Changed
|
data/Readme.md
CHANGED
|
@@ -53,18 +53,14 @@ Postgres, from an informal reading of the docs, will never support the concept o
|
|
|
53
53
|
and make sure to require 'active_record_host_pool' in some way.
|
|
54
54
|
|
|
55
55
|
## Testing
|
|
56
|
-
You need a local user called 'john-doe'.
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
CREATE USER 'john-doe'@'localhost';
|
|
60
|
-
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX ON *.* TO 'john-doe'@'localhost';
|
|
61
|
-
FLUSH PRIVILEGES;
|
|
57
|
+
TestContainers will take care of setting up the necessary MySQL servers for you. You just need to have e.g. Docker running.
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
Run e.g.
|
|
64
60
|
|
|
65
61
|
BUNDLE_GEMFILE=gemfiles/rails6.1.gemfile bundle exec rake test
|
|
66
62
|
|
|
67
|
-
|
|
63
|
+
or
|
|
68
64
|
|
|
69
65
|
BUNDLE_GEMFILE=gemfiles/rails6.1.gemfile ruby test/test_arhp.rb --seed 19911 --verbose
|
|
70
66
|
|
|
@@ -62,7 +62,7 @@ module ActiveRecordHostPool
|
|
|
62
62
|
_desired_database_changed? ||
|
|
63
63
|
_real_connection_changed?
|
|
64
64
|
)
|
|
65
|
-
log(
|
|
65
|
+
log(select_db_log_arg, "SQL") do
|
|
66
66
|
clear_cache!
|
|
67
67
|
real_connection.select_db(_host_pool_desired_database)
|
|
68
68
|
end
|
|
@@ -71,22 +71,23 @@ module ActiveRecordHostPool
|
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
if ActiveRecord.version < Gem::Version.new("8.2.a")
|
|
75
|
+
def select_db_log_arg
|
|
76
|
+
"select_db #{_host_pool_desired_database}"
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
def select_db_log_arg
|
|
80
|
+
ActiveRecord::ConnectionAdapters::QueryIntent.new(processed_sql: "select_db #{_host_pool_desired_database}")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
74
84
|
def _desired_database_changed?
|
|
75
85
|
_host_pool_desired_database != @_cached_current_database
|
|
76
86
|
end
|
|
77
87
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
when "7.1"
|
|
81
|
-
def _real_connection_object_id
|
|
82
|
-
@connection.object_id
|
|
83
|
-
end
|
|
84
|
-
else
|
|
85
|
-
def _real_connection_object_id
|
|
86
|
-
@raw_connection.object_id
|
|
87
|
-
end
|
|
88
|
+
def _real_connection_object_id
|
|
89
|
+
@raw_connection.object_id
|
|
88
90
|
end
|
|
89
|
-
# rubocop:enable Lint/DuplicateMethods
|
|
90
91
|
|
|
91
92
|
def _real_connection_changed?
|
|
92
93
|
_real_connection_object_id != @_cached_connection_object_id
|
|
@@ -6,6 +6,16 @@ require "delegate"
|
|
|
6
6
|
# for each call to the connection. upon executing a statement, the connection will switch to that database.
|
|
7
7
|
module ActiveRecordHostPool
|
|
8
8
|
class ConnectionProxy < Delegator
|
|
9
|
+
class << self
|
|
10
|
+
def class_eval
|
|
11
|
+
raise "You probably want to call .class_eval on the ActiveRecord connection adapter and not on ActiveRecordHostPool's connection proxy. Use .arhp_connection_proxy_class_eval if you _really_ know what you're doing."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def arhp_connection_proxy_class_eval(...)
|
|
15
|
+
method(:class_eval).super_method.call(...)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
9
19
|
attr_reader :database
|
|
10
20
|
def initialize(cx, database)
|
|
11
21
|
super(cx)
|
|
@@ -26,11 +36,6 @@ module ActiveRecordHostPool
|
|
|
26
36
|
@cx
|
|
27
37
|
end
|
|
28
38
|
|
|
29
|
-
# this is bad. I know. but it allows folks who class_eval on connection.class to do so
|
|
30
|
-
def class
|
|
31
|
-
@cx.class
|
|
32
|
-
end
|
|
33
|
-
|
|
34
39
|
def expects(*args)
|
|
35
40
|
@cx.send(:expects, *args)
|
|
36
41
|
end
|
|
@@ -51,35 +51,18 @@ module ActiveRecordHostPool
|
|
|
51
51
|
|
|
52
52
|
attr_reader :pool_config
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
Kernel.raise
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def _unproxied_connection(*args)
|
|
66
|
-
_connection_pool.connection(*args)
|
|
67
|
-
end
|
|
68
|
-
else
|
|
69
|
-
def lease_connection(*args)
|
|
70
|
-
real_connection = _unproxied_connection(*args)
|
|
71
|
-
_connection_proxy_for(real_connection, @config[:database])
|
|
72
|
-
rescue *RESCUABLE_DB_ERROR, ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid
|
|
73
|
-
_connection_pools.delete(_pool_key)
|
|
74
|
-
Kernel.raise
|
|
75
|
-
end
|
|
76
|
-
alias_method :connection, :lease_connection
|
|
54
|
+
def lease_connection(*args)
|
|
55
|
+
real_connection = _unproxied_connection(*args)
|
|
56
|
+
_connection_proxy_for(real_connection, @config[:database])
|
|
57
|
+
rescue *RESCUABLE_DB_ERROR, ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid
|
|
58
|
+
_connection_pools.delete(_pool_key)
|
|
59
|
+
Kernel.raise
|
|
60
|
+
end
|
|
61
|
+
alias_method :connection, :lease_connection
|
|
77
62
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
end
|
|
63
|
+
def _unproxied_connection(*args)
|
|
64
|
+
_connection_pool.lease_connection(*args)
|
|
81
65
|
end
|
|
82
|
-
# rubocop:enable Lint/DuplicateMethods
|
|
83
66
|
|
|
84
67
|
# by the time we are patched into ActiveRecord, the current thread has already established
|
|
85
68
|
# a connection. thus we need to patch both connection and checkout/checkin
|
|
@@ -93,49 +76,39 @@ module ActiveRecordHostPool
|
|
|
93
76
|
_connection_pool.checkin(cx)
|
|
94
77
|
end
|
|
95
78
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
yield cx
|
|
101
|
-
ensure
|
|
102
|
-
checkin cx
|
|
103
|
-
end
|
|
104
|
-
else
|
|
105
|
-
def with_connection(prevent_permanent_checkout: false) # rubocop:disable Lint/DuplicateMethods
|
|
106
|
-
real_connection_lease = _connection_pool.send(:connection_lease)
|
|
107
|
-
sticky_was = real_connection_lease.sticky
|
|
108
|
-
real_connection_lease.sticky = false if prevent_permanent_checkout
|
|
109
|
-
|
|
110
|
-
if real_connection_lease.connection
|
|
111
|
-
begin
|
|
112
|
-
yield _connection_proxy_for(real_connection_lease.connection, @config[:database])
|
|
113
|
-
ensure
|
|
114
|
-
real_connection_lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was
|
|
115
|
-
end
|
|
116
|
-
else
|
|
117
|
-
begin
|
|
118
|
-
real_connection_lease.connection = _unproxied_connection
|
|
119
|
-
yield _connection_proxy_for(real_connection_lease.connection, @config[:database])
|
|
120
|
-
ensure
|
|
121
|
-
real_connection_lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was
|
|
122
|
-
_connection_pool.release_connection(real_connection_lease) unless real_connection_lease.sticky
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
79
|
+
def with_connection(prevent_permanent_checkout: false) # rubocop:disable Lint/DuplicateMethods
|
|
80
|
+
real_connection_lease = _connection_pool.send(:connection_lease)
|
|
81
|
+
sticky_was = real_connection_lease.sticky
|
|
82
|
+
real_connection_lease.sticky = false if prevent_permanent_checkout
|
|
126
83
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
84
|
+
if real_connection_lease.connection
|
|
85
|
+
begin
|
|
86
|
+
yield _connection_proxy_for(real_connection_lease.connection, @config[:database])
|
|
87
|
+
ensure
|
|
88
|
+
real_connection_lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
begin
|
|
92
|
+
real_connection_lease.connection = _unproxied_connection
|
|
93
|
+
yield _connection_proxy_for(real_connection_lease.connection, @config[:database])
|
|
94
|
+
ensure
|
|
95
|
+
real_connection_lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was
|
|
96
|
+
_connection_pool.release_connection(real_connection_lease) unless real_connection_lease.sticky
|
|
131
97
|
end
|
|
132
98
|
end
|
|
133
|
-
|
|
99
|
+
end
|
|
134
100
|
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
def active_connection?
|
|
102
|
+
real_connection_lease = _connection_pool.send(:connection_lease)
|
|
103
|
+
if real_connection_lease.connection
|
|
104
|
+
_connection_proxy_for(real_connection_lease.connection, @config[:database])
|
|
137
105
|
end
|
|
138
106
|
end
|
|
107
|
+
alias_method :active_connection, :active_connection?
|
|
108
|
+
|
|
109
|
+
def schema_cache
|
|
110
|
+
@schema_cache ||= ActiveRecord::ConnectionAdapters::BoundSchemaReflection.new(_connection_pool.schema_reflection, self)
|
|
111
|
+
end
|
|
139
112
|
|
|
140
113
|
def disconnect!
|
|
141
114
|
p = _connection_pool(false)
|
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: 4.
|
|
4
|
+
version: 4.3.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: 2025-
|
|
14
|
+
date: 2025-11-11 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: activerecord
|
|
@@ -19,14 +19,14 @@ dependencies:
|
|
|
19
19
|
requirements:
|
|
20
20
|
- - ">="
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: 7.
|
|
22
|
+
version: 7.2.0
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
27
|
- - ">="
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: 7.
|
|
29
|
+
version: 7.2.0
|
|
30
30
|
description: ''
|
|
31
31
|
email:
|
|
32
32
|
- bquorning@zendesk.com
|
|
@@ -42,7 +42,6 @@ files:
|
|
|
42
42
|
- MIT-LICENSE
|
|
43
43
|
- Readme.md
|
|
44
44
|
- lib/active_record_host_pool.rb
|
|
45
|
-
- lib/active_record_host_pool/clear_query_cache_patch.rb
|
|
46
45
|
- lib/active_record_host_pool/connection_adapter_mixin.rb
|
|
47
46
|
- lib/active_record_host_pool/connection_proxy.rb
|
|
48
47
|
- lib/active_record_host_pool/pool_proxy.rb
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# ActiveRecord 6.0 introduced multiple database support. With that, an update
|
|
4
|
-
# has been made in https://github.com/rails/rails/pull/35089 to ensure that
|
|
5
|
-
# all query caches are cleared across connection handlers and pools. If you
|
|
6
|
-
# write on one connection, the other connection will have the update that
|
|
7
|
-
# occurred.
|
|
8
|
-
#
|
|
9
|
-
# This broke ARHP which implements its own pool, allowing you to access
|
|
10
|
-
# multiple databases with the same connection (e.g. 1 connection for 100
|
|
11
|
-
# shards on the same server).
|
|
12
|
-
#
|
|
13
|
-
# This patch maintains the reference to the database during the cache clearing
|
|
14
|
-
# to ensure that the database doesn't get swapped out mid-way into an
|
|
15
|
-
# operation.
|
|
16
|
-
#
|
|
17
|
-
# This is a private Rails API and may change in future releases as they're
|
|
18
|
-
# actively working on sharding in Rails 6 and above.
|
|
19
|
-
module ActiveRecordHostPool
|
|
20
|
-
# For Rails 7.1.
|
|
21
|
-
module ClearQueryCachePatch
|
|
22
|
-
def clear_query_caches_for_current_thread
|
|
23
|
-
connection_handler.each_connection_pool do |pool|
|
|
24
|
-
pool._unproxied_connection.clear_query_cache if pool.active_connection?
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
|
31
|
-
when "7.1"
|
|
32
|
-
# Fix https://github.com/rails/rails/commit/401e2f24161ed6047ae33c322aaf6584b7728ab9
|
|
33
|
-
ActiveRecord::Base.singleton_class.prepend(ActiveRecordHostPool::ClearQueryCachePatch)
|
|
34
|
-
end
|