active_record_host_pool 1.1.0 → 1.1.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dc3e41230c1cc7b208056d7f6fe99abe717e190b55cdca3ff5df9f1513fcad1
|
4
|
+
data.tar.gz: 92f1982d46da0644184083a78d72ad878d54ff70413f347fcb67bc3890cfaeca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3e4c62f5aee3ae968622ca9a7fef59fd9974c4153c244c312715036f6753a0ec58ba3083247bb9a4b9479db3a3c55a8182c85ae320d273ad90a1084ea745b46
|
7
|
+
data.tar.gz: 1fcec2e7e23272e50894a19bd4fc195e0360089d3a5e44f98fc6a589723f3a6bb8dae2276dbeeec31f05f87f89641308909412b28f73f929bc2358605fe30937
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
require 'active_record'
|
5
|
+
require 'active_record_host_pool/connection_adapter_mixin'
|
6
|
+
|
7
|
+
# this module sits in between ConnectionHandler and a bunch of different ConnectionPools (one per host).
|
8
|
+
# when a connection is requested, it goes like:
|
9
|
+
# ActiveRecordClass -> ConnectionHandler#connection
|
10
|
+
# ConnectionHandler#connection -> (find or create PoolProxy)
|
11
|
+
# PoolProxy -> shared list of Pools
|
12
|
+
# Pool actually gives back a connection, then PoolProxy turns this
|
13
|
+
# into a ConnectionProxy that can inform (on execute) which db we should be on.
|
14
|
+
|
15
|
+
module ActiveRecordHostPool
|
16
|
+
# Sits between ConnectionHandler and a bunch of different ConnectionPools (one per host).
|
17
|
+
class PoolProxy < Delegator
|
18
|
+
def initialize(pool_config)
|
19
|
+
super(pool_config)
|
20
|
+
@pool_config = pool_config
|
21
|
+
@config = pool_config.db_config.configuration_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def __getobj__
|
25
|
+
_connection_pool
|
26
|
+
end
|
27
|
+
|
28
|
+
def __setobj__(pool_config)
|
29
|
+
@pool_config = pool_config
|
30
|
+
@config = pool_config.db_config.configuration_hash
|
31
|
+
@_pool_key = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :pool_config
|
35
|
+
|
36
|
+
def connection(*args)
|
37
|
+
real_connection = _connection_pool.connection(*args)
|
38
|
+
_connection_proxy_for(real_connection, @config[:database])
|
39
|
+
rescue Mysql2::Error, ActiveRecord::NoDatabaseError
|
40
|
+
_connection_pools.delete(_pool_key)
|
41
|
+
Kernel.raise
|
42
|
+
end
|
43
|
+
|
44
|
+
# by the time we are patched into ActiveRecord, the current thread has already established
|
45
|
+
# a connection. thus we need to patch both connection and checkout/checkin
|
46
|
+
def checkout(*args, &block)
|
47
|
+
cx = _connection_pool.checkout(*args, &block)
|
48
|
+
_connection_proxy_for(cx, @config[:database])
|
49
|
+
end
|
50
|
+
|
51
|
+
def checkin(cx)
|
52
|
+
cx = cx.unproxied
|
53
|
+
_connection_pool.checkin(cx)
|
54
|
+
end
|
55
|
+
|
56
|
+
def with_connection
|
57
|
+
cx = checkout
|
58
|
+
yield cx
|
59
|
+
ensure
|
60
|
+
checkin cx
|
61
|
+
end
|
62
|
+
|
63
|
+
def disconnect!
|
64
|
+
p = _connection_pool(false)
|
65
|
+
return unless p
|
66
|
+
|
67
|
+
p.disconnect!
|
68
|
+
p.automatic_reconnect = true if p.respond_to?(:automatic_reconnect=)
|
69
|
+
_clear_connection_proxy_cache
|
70
|
+
end
|
71
|
+
|
72
|
+
def automatic_reconnect=(value)
|
73
|
+
p = _connection_pool(false)
|
74
|
+
return unless p
|
75
|
+
|
76
|
+
p.automatic_reconnect = value if p.respond_to?(:automatic_reconnect=)
|
77
|
+
end
|
78
|
+
|
79
|
+
def clear_reloadable_connections!
|
80
|
+
_connection_pool.clear_reloadable_connections!
|
81
|
+
_clear_connection_proxy_cache
|
82
|
+
end
|
83
|
+
|
84
|
+
def release_connection(*args)
|
85
|
+
p = _connection_pool(false)
|
86
|
+
return unless p
|
87
|
+
|
88
|
+
p.release_connection(*args)
|
89
|
+
end
|
90
|
+
|
91
|
+
def flush!
|
92
|
+
p = _connection_pool(false)
|
93
|
+
return unless p
|
94
|
+
|
95
|
+
p.flush!
|
96
|
+
end
|
97
|
+
|
98
|
+
def discard!
|
99
|
+
p = _connection_pool(false)
|
100
|
+
return unless p
|
101
|
+
|
102
|
+
p.discard!
|
103
|
+
|
104
|
+
# All connections in the pool (even if they're currently
|
105
|
+
# leased!) have just been discarded, along with the pool itself.
|
106
|
+
# Any further interaction with the pool (except #pool_config and #schema_cache)
|
107
|
+
# is undefined.
|
108
|
+
# Remove the connection for the given key so a new one can be created in its place
|
109
|
+
_connection_pools.delete(_pool_key)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def _connection_pools
|
115
|
+
@@_connection_pools ||= {}
|
116
|
+
end
|
117
|
+
|
118
|
+
def _pool_key
|
119
|
+
@_pool_key ||= "#{@config[:host]}/#{@config[:port]}/#{@config[:socket]}/" \
|
120
|
+
"#{@config[:username]}/#{replica_configuration? && 'replica'}"
|
121
|
+
end
|
122
|
+
|
123
|
+
def _connection_pool(auto_create = true)
|
124
|
+
pool = _connection_pools[_pool_key]
|
125
|
+
if pool.nil? && auto_create
|
126
|
+
pool = _connection_pools[_pool_key] = ActiveRecord::ConnectionAdapters::ConnectionPool.new(@pool_config)
|
127
|
+
end
|
128
|
+
pool
|
129
|
+
end
|
130
|
+
|
131
|
+
def _connection_proxy_for(connection, database)
|
132
|
+
@connection_proxy_cache ||= {}
|
133
|
+
key = [connection, database]
|
134
|
+
|
135
|
+
@connection_proxy_cache[key] ||= begin
|
136
|
+
cx = ActiveRecordHostPool::ConnectionProxy.new(connection, database)
|
137
|
+
cx.execute('select 1')
|
138
|
+
cx
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def _clear_connection_proxy_cache
|
143
|
+
@connection_proxy_cache = {}
|
144
|
+
end
|
145
|
+
|
146
|
+
def replica_configuration?
|
147
|
+
@config[:replica] || @config[:slave]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# For versions of Rails < 6.1
|
4
|
+
|
5
|
+
require 'delegate'
|
6
|
+
require 'active_record'
|
7
|
+
require 'active_record_host_pool/connection_adapter_mixin'
|
8
|
+
|
9
|
+
# this module sits in between ConnectionHandler and a bunch of different ConnectionPools (one per host).
|
10
|
+
# when a connection is requested, it goes like:
|
11
|
+
# ActiveRecordClass -> ConnectionHandler#connection
|
12
|
+
# ConnectionHandler#connection -> (find or create PoolProxy)
|
13
|
+
# PoolProxy -> shared list of Pools
|
14
|
+
# Pool actually gives back a connection, then PoolProxy turns this
|
15
|
+
# into a ConnectionProxy that can inform (on execute) which db we should be on.
|
16
|
+
|
17
|
+
module ActiveRecordHostPool
|
18
|
+
# Sits between ConnectionHandler and a bunch of different ConnectionPools (one per host).
|
19
|
+
class PoolProxy < Delegator
|
20
|
+
def initialize(spec)
|
21
|
+
super(spec)
|
22
|
+
@spec = spec
|
23
|
+
@config = spec.config
|
24
|
+
end
|
25
|
+
|
26
|
+
def __getobj__
|
27
|
+
_connection_pool
|
28
|
+
end
|
29
|
+
|
30
|
+
def __setobj__(spec)
|
31
|
+
@spec = spec
|
32
|
+
@config = spec.config
|
33
|
+
@_pool_key = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :spec
|
37
|
+
|
38
|
+
def connection(*args)
|
39
|
+
real_connection = _connection_pool.connection(*args)
|
40
|
+
_connection_proxy_for(real_connection, @config[:database])
|
41
|
+
rescue Mysql2::Error, ActiveRecord::NoDatabaseError
|
42
|
+
_connection_pools.delete(_pool_key)
|
43
|
+
Kernel.raise
|
44
|
+
end
|
45
|
+
|
46
|
+
# by the time we are patched into ActiveRecord, the current thread has already established
|
47
|
+
# a connection. thus we need to patch both connection and checkout/checkin
|
48
|
+
def checkout(*args, &block)
|
49
|
+
cx = _connection_pool.checkout(*args, &block)
|
50
|
+
_connection_proxy_for(cx, @config[:database])
|
51
|
+
end
|
52
|
+
|
53
|
+
def checkin(cx)
|
54
|
+
cx = cx.unproxied
|
55
|
+
_connection_pool.checkin(cx)
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_connection
|
59
|
+
cx = checkout
|
60
|
+
yield cx
|
61
|
+
ensure
|
62
|
+
checkin cx
|
63
|
+
end
|
64
|
+
|
65
|
+
def disconnect!
|
66
|
+
p = _connection_pool(false)
|
67
|
+
return unless p
|
68
|
+
|
69
|
+
p.disconnect!
|
70
|
+
p.automatic_reconnect = true if p.respond_to?(:automatic_reconnect=)
|
71
|
+
_clear_connection_proxy_cache
|
72
|
+
end
|
73
|
+
|
74
|
+
def automatic_reconnect=(value)
|
75
|
+
p = _connection_pool(false)
|
76
|
+
return unless p
|
77
|
+
|
78
|
+
p.automatic_reconnect = value if p.respond_to?(:automatic_reconnect=)
|
79
|
+
end
|
80
|
+
|
81
|
+
def clear_reloadable_connections!
|
82
|
+
_connection_pool.clear_reloadable_connections!
|
83
|
+
_clear_connection_proxy_cache
|
84
|
+
end
|
85
|
+
|
86
|
+
def release_connection(*args)
|
87
|
+
p = _connection_pool(false)
|
88
|
+
return unless p
|
89
|
+
|
90
|
+
p.release_connection(*args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def flush!
|
94
|
+
p = _connection_pool(false)
|
95
|
+
return unless p
|
96
|
+
|
97
|
+
p.flush!
|
98
|
+
end
|
99
|
+
|
100
|
+
def discard!
|
101
|
+
p = _connection_pool(false)
|
102
|
+
return unless p
|
103
|
+
|
104
|
+
p.discard!
|
105
|
+
|
106
|
+
# All connections in the pool (even if they're currently
|
107
|
+
# leased!) have just been discarded, along with the pool itself.
|
108
|
+
# Any further interaction with the pool (except #spec and #schema_cache)
|
109
|
+
# is undefined.
|
110
|
+
# Remove the connection for the given key so a new one can be created in its place
|
111
|
+
_connection_pools.delete(_pool_key)
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def _connection_pools
|
117
|
+
@@_connection_pools ||= {}
|
118
|
+
end
|
119
|
+
|
120
|
+
def _pool_key
|
121
|
+
@_pool_key ||= "#{@config[:host]}/#{@config[:port]}/#{@config[:socket]}/" \
|
122
|
+
"#{@config[:username]}/#{replica_configuration? && 'replica'}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def _connection_pool(auto_create = true)
|
126
|
+
pool = _connection_pools[_pool_key]
|
127
|
+
if pool.nil? && auto_create
|
128
|
+
pool = _connection_pools[_pool_key] = ActiveRecord::ConnectionAdapters::ConnectionPool.new(@spec)
|
129
|
+
end
|
130
|
+
pool
|
131
|
+
end
|
132
|
+
|
133
|
+
def _connection_proxy_for(connection, database)
|
134
|
+
@connection_proxy_cache ||= {}
|
135
|
+
key = [connection, database]
|
136
|
+
|
137
|
+
@connection_proxy_cache[key] ||= begin
|
138
|
+
cx = ActiveRecordHostPool::ConnectionProxy.new(connection, database)
|
139
|
+
cx.execute('select 1')
|
140
|
+
cx
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def _clear_connection_proxy_cache
|
145
|
+
@connection_proxy_cache = {}
|
146
|
+
end
|
147
|
+
|
148
|
+
def replica_configuration?
|
149
|
+
@config[:replica] || @config[:slave]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
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: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Quorning
|
@@ -163,6 +163,8 @@ files:
|
|
163
163
|
- lib/active_record_host_pool/connection_adapter_mixin.rb
|
164
164
|
- lib/active_record_host_pool/connection_proxy.rb
|
165
165
|
- lib/active_record_host_pool/pool_proxy.rb
|
166
|
+
- lib/active_record_host_pool/pool_proxy_6_1.rb
|
167
|
+
- lib/active_record_host_pool/pool_proxy_legacy.rb
|
166
168
|
- lib/active_record_host_pool/version.rb
|
167
169
|
- test/database.yml
|
168
170
|
- test/helper.rb
|