fresh_connection 2.3.0 → 2.3.1

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
  SHA1:
3
- metadata.gz: 5209747ee5ebffd0721b5c2dbcf20940721867c4
4
- data.tar.gz: 022c9dce7d03c2ca0bc0732022ea70099df547df
3
+ metadata.gz: deb0b581ea9aecc3c27b3d32a6a14c93ee3a543f
4
+ data.tar.gz: 0323e5cd09c34895529a49d339c00797c45cfa07
5
5
  SHA512:
6
- metadata.gz: 700f794d9cb774036025d53b6cf471ffd83c8a9de8b1188c1d0bf153e292c98c69804473a1e20bf535e18fc4be771d264585db463affeeda1b7b2303942aa868
7
- data.tar.gz: d4f6fbea8f6debe411aa22f603a3e463bc03986dbefd05ded39374fe645641811e862814f09c34de2d38881ceb6e946ab8b4b8cdaed638bbf226337c0bbb0505
6
+ metadata.gz: 5163c26ac8a920f5b5f3485d4049b147ae826075ba8cfb6c2b1f6adf2b3e9966c046304932851c2b0b64228892c08569c2b5d81d7ef0bd21ae5db025e2f28bbc
7
+ data.tar.gz: 71e16efe75624fd56cf02374bb8db2fa5e94c3038c3b044dbb8df1ba689ed797f1e5254bb65fd31a9d4276125c876f13edb3db4d5dc8142ce002ae5ec18f125d
data/README.md CHANGED
@@ -4,16 +4,16 @@
4
4
  **FreshConnection** provides access to one or more configured database replicas.
5
5
 
6
6
  For example:
7
- ```
7
+
8
+ ```text
8
9
  Rails ------------ DB Master
9
10
  |
10
11
  +---- DB Replica
11
-
12
12
  ```
13
13
 
14
- or:
14
+ or
15
15
 
16
- ```
16
+ ```text
17
17
  Rails -------+---- DB Master
18
18
  |
19
19
  | +------ DB Replica1
@@ -23,16 +23,13 @@ Rails -------+---- DB Master
23
23
  +------ DB Replica2
24
24
  ```
25
25
 
26
- FreshConnction connects one or more configured DB replicas, or with multiple
27
- replicas behind a DB query load balancer.
26
+ FreshConnction connects one or more configured DB replicas, or with multiple replicas behind a DB query load balancer.
28
27
 
29
28
  - Read queries go to the DB replica.
30
29
  - Write queries go to the DB master.
31
30
  - Within a transaction, all queries go to the DB master.
32
31
 
33
- If you wish to use multiple DB replicas on any given connection but not have
34
- a load balancer (such as [`pgbouncer`](https://pgbouncer.github.io) for Posgres
35
- databases), you can use [EbisuConnection](https://github.com/tsukasaoishi/ebisu_connection).
32
+ If you wish to use multiple DB replicas on any given connection but do not have a load balancer (such as [`pgbouncer`](https://pgbouncer.github.io) for Posgres databases), you can use [EbisuConnection](https://github.com/tsukasaoishi/ebisu_connection).
36
33
 
37
34
  ## Usage
38
35
  ### Access to the DB Replica
@@ -46,7 +43,8 @@ Account.count
46
43
 
47
44
  ### Access to the DB Master
48
45
  If you wish to ensure that queries are directed to the DB master, call `read_master`.
49
- Before version 0.4.3, `readonly(false)` must be used.
46
+
47
+ > Note: Before version 0.4.3, `readonly(false)` must be used.
50
48
 
51
49
  ```ruby
52
50
  Article.where(id: 1).read_master
@@ -73,9 +71,10 @@ old_article.destroy
73
71
  ```
74
72
 
75
73
  ## ActiveRecord Versions Supported
76
- FreshConnection supports ActiveRecord version 4.2 or later.
77
- If you are using Rails 4.1 or 4.0, you can use FreshConnection version 2.1.2 or before.
78
- If you are using Rails 3.2, you can use FreshConnection version 1.0.0 or before.
74
+
75
+ - FreshConnection supports ActiveRecord version 4.2 or later.
76
+ - If you are using Rails 4.1 or 4.0, you can use FreshConnection version 2.1.2 or before.
77
+ - If you are using Rails 3.2, you can use FreshConnection version 1.0.0 or before.
79
78
 
80
79
  ## Databases Supported
81
80
  FreshConnection currently supports MySQL and PostgreSQL.
@@ -100,9 +99,8 @@ $ gem install fresh_connection
100
99
  ```
101
100
 
102
101
  ### Variant Installation For Use With Some Other ActiveRecord Gems
103
- If you are using NewRelic or other gems that insert themselves into the
104
- ActiveRecord call-chain using `method_alias`, then a slight variation on the
105
- installation and configuration is required.
102
+
103
+ If you are using NewRelic or other gems that insert themselves into the ActiveRecord call-chain using `method_alias`, then a slight variation on the installation and configuration is required.
106
104
 
107
105
  In the `Gemfile`, use:
108
106
 
@@ -154,12 +152,10 @@ production:
154
152
  host: <%= ENV['DB_REPLICA_HOST'] %>
155
153
  ```
156
154
 
157
- `replica` is the configuration used for connecting read-only queries to the
158
- database replica. All other connections will use the database master settings.
155
+ `replica` is the configuration used for connecting read-only queries to the database replica. All other connections will use the database master settings.
159
156
 
160
157
  ### Multiple DB Replicas
161
- If you want to use multiple configured DB replicas, the configuration can
162
- contain multiple `replica` stanzas in the configuration file `config/database.yml`.
158
+ If you want to use multiple configured DB replicas, the configuration can contain multiple `replica` stanzas in the configuration file `config/database.yml`.
163
159
 
164
160
  For example:
165
161
 
@@ -186,9 +182,7 @@ production:
186
182
  host: <%= ENV['DB_ADMIN_REPLICA_HOST'] %>
187
183
  ```
188
184
 
189
- The custom replica stanza can then be applied as an argument to the
190
- `establish_fresh_connection` method in the models that should use it. For
191
- example:
185
+ The custom replica stanza can then be applied as an argument to the `establish_fresh_connection` method in the models that should use it. For example:
192
186
 
193
187
  ```ruby
194
188
  class AdminUser < ActiveRecord::Base
@@ -196,8 +190,7 @@ class AdminUser < ActiveRecord::Base
196
190
  end
197
191
  ```
198
192
 
199
- The child (sub) classes of the configured model will inherit the same access
200
- as the parent class. Example:
193
+ The child (sub) classes of the configured model will inherit the same access as the parent class. Example:
201
194
 
202
195
  ```ruby
203
196
  class AdminBase < ActiveRecord::Base
@@ -214,18 +207,54 @@ class Customer < ActiveRecord::Base
214
207
  end
215
208
  ```
216
209
 
217
- The `AdminUser` and `Benefit` models will access the database configured for
218
- the `admin_replica` group.
210
+ The `AdminUser` and `Benefit` models will access the database configured for the `admin_replica` group.
211
+
212
+ The `Customer` model will use the default connections: read-only queries will connect to the standard DB replica, and state-changing queries will connect to the DB master.
213
+
214
+ ### Replica Configuration With Environment Variables
215
+
216
+
217
+ Alternative to using a configuration in the `database.yml` file, it is possible to completely specify the replica access components using environment variables.
218
+
219
+ The environment variables corresponding to the `:replica` group are `DATABASE_REPLICA_URL` and `DATABASE_REPLICA1_URL`, with the latter being used only if the former is not defined.
220
+
221
+ The URL value is a [URL](https://en.wikipedia.org/wiki/URL) string with the following components:
222
+
223
+ _adapter://dbuser:dbpass@dbhost:dbport/dbname?querypath_
224
+
225
+ where the components are:
226
+
227
+ | Component | Purpose | Examples |
228
+ | --------- | ------- | --------- |
229
+ | _adapter_ | Declares the database adapter | `mysql`, `postgresql` |
230
+ | _dbuser_ | The login for the database | `root`, `postgres` |
231
+ | _dbpass_ | The password for the database | |
232
+ | _dbhost_ | The hostname for the database | `db1`, `localhost` |
233
+ | _dbport_ | The port for the database connection | `3306`, `5432` |
234
+ | _dbname_ | The name of the database | `mydb`, `appdb`, etc. |
235
+ | _querypath_ | One or more variable assignments: _var1=val1_, separated by '&' | `pools=5&reconnect=true` |
236
+
237
+
238
+ For example, here is a URL appropriate for a connection to a test database on the local host, on a custom port:
239
+
240
+ export DATABASE_REPLICA_URL='postgresql://root:somepw@localhost:6432/test_db?pool=5&reconnect=true
241
+
242
+ ### Multiple Replica Environment Variables
243
+
244
+ To specific URLs for multiple replicas, replace the string `REPLICA` in the environment variable name with the replica name, in upper case. See the examples for replicas: `:replica1`, `:replica2`, and `:admin_replica`
245
+
246
+
247
+ ENVIRONMENT_REPLICA1_URL='mysql://localhost/dbreplica1?pool=5&reconnect=true'
248
+ ENVIRONMENT_REPLICA2_URL='postgresql://localhost:6432/ro_db?pool=5&reconnect=true'
249
+ ENVIRONMENT_ADMIN_REPLICA_URL='postgresql://localhost:6432/admin_db?pool=5&reconnect=true'
219
250
 
220
- The `Customer` model will use the default connections: read-only queries will
221
- connect to the standard DB replica, and state-changing queries will connect to
222
- the DB master.
251
+ ### Special-Case Replica URL
223
252
 
253
+ When `:replica` is used but `DATABASE_REPLICA_URL` is *not* defined, then the value of `DATABASE_REPLICA1_URL` will be used if it is defined.
224
254
 
225
255
  ### Master-only Models
226
256
 
227
- It is possible to declare that specific models always use the DB master for all connections, using
228
- the `master_db_only!` method:
257
+ It is possible to declare that specific models always use the DB master for all connections, using the `master_db_only!` method:
229
258
 
230
259
  ```ruby
231
260
  class CustomerState < ActiveRecord::Base
@@ -237,9 +266,7 @@ All queries generated by methods on the `CustomerState` model will be directed t
237
266
 
238
267
  ### Using FreshConnection With Unicorn
239
268
 
240
- When using FreshConnection with Unicorn (or any other multi-processing web
241
- server which restarts processes on the fly), connection management needs
242
- special attention during startup:
269
+ When using FreshConnection with Unicorn (or any other multi-processing web server which restarts processes on the fly), connection management needs special attention during startup:
243
270
 
244
271
  ```ruby
245
272
  before_fork do |server, worker|
@@ -256,9 +283,7 @@ end
256
283
  ```
257
284
 
258
285
  ### Replica Connection Manager
259
- The default replica connection manager is `FreshConnection::ConnectionManager`.
260
- If an alternative (custom) replica connection manager is desired, this can be done
261
- with a simple assignment within a Rails initializer:
286
+ The default replica connection manager is `FreshConnection::ConnectionManager`. If an alternative (custom) replica connection manager is desired, this can be done with a simple assignment within a Rails initializer:
262
287
 
263
288
  `config/initializers/fresh_connection.rb`:
264
289
 
@@ -266,8 +291,7 @@ with a simple assignment within a Rails initializer:
266
291
  FreshConnection.connection_manager = MyOwnReplicaConnection
267
292
  ```
268
293
 
269
- The `MyOwnReplicaConnection` class should inherit from
270
- `FreshConnection::AbstractConnectionManager`, which has this interface:
294
+ The `MyOwnReplicaConnection` class should inherit from `FreshConnection::AbstractConnectionManager`, which has this interface:
271
295
 
272
296
  ```ruby
273
297
  class MyOwnReplicaConnection < FreshConnection::AbstractConnectionManager
@@ -305,12 +329,12 @@ end
305
329
 
306
330
  ## Test
307
331
 
308
- I'm glad that you would test!
309
- To run the test suite, `mysql` must be installed.
332
+ I'm glad that you would like to test!
333
+ To run the test suite, both `mysql` and `postgresql` must be installed.
310
334
 
311
335
  ### Test Configuration
312
336
 
313
- First, configure the test `mysql` server in `spec/database.yml`.
337
+ First, configure the test servers in `test/config/*.yml`
314
338
 
315
339
  Then, run:
316
340
 
data/Rakefile CHANGED
@@ -1,18 +1,20 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rake/testtask'
3
3
 
4
- desc 'Run mysql2 and postgresql test'
4
+ desc 'Run mysql2 and postgresql tests'
5
5
  task :test do
6
6
  Rake::Task["test:mysql2"].invoke
7
+ Rake::Task["test:mysql2_url"].invoke
7
8
  Rake::Task["test:postgresql"].invoke
9
+ Rake::Task["test:postgresql_url"].invoke
8
10
  end
9
11
 
10
12
  namespace :test do
11
- %w(mysql2 postgresql).each do |db|
12
- Rake::TestTask.new(db) do |t|
13
+ %w(mysql2 postgresql mysql2_url postgresql_url).each do |test_name|
14
+ Rake::TestTask.new(test_name) do |t|
13
15
  t.libs << "test"
14
16
  t.libs << "lib"
15
- t.test_files = FileList["test/config/prepare_#{db}", 'test/**/*_test.rb']
17
+ t.test_files = FileList["test/config/prepare_#{test_name}", 'test/**/*_test.rb']
16
18
  t.verbose = true
17
19
  end
18
20
  end
@@ -7,7 +7,7 @@ module FreshConnection
7
7
  return unless name == :slave_connection
8
8
 
9
9
  ActiveSupport::Deprecation.warn(
10
- "'slave_connection' has been deprecated. use 'replica_connection' insted."
10
+ "'slave_connection' has been deprecated. use 'replica_connection' instead."
11
11
  )
12
12
  end
13
13
  end
@@ -22,7 +22,7 @@ module FreshConnection
22
22
 
23
23
  def slave_group
24
24
  ActiveSupport::Deprecation.warn(
25
- "'slave_group' is deprecated and will removed from version 2.4.0. use 'replica_group' insted."
25
+ "'slave_group' is deprecated and will removed from version 2.4.0. use 'replica_group' instead."
26
26
  )
27
27
 
28
28
  replica_group
@@ -1,11 +1,14 @@
1
1
  require 'active_support/deprecation'
2
2
  require 'active_support/core_ext/hash/keys'
3
+ require 'active_support/hash_with_indifferent_access'
4
+ require 'active_support/core_ext/hash/indifferent_access'
3
5
 
4
6
  module FreshConnection
5
7
  class ConnectionFactory
6
- def initialize(group, modify_spec = {})
8
+ def initialize(group, modify_spec = nil)
7
9
  @group = group.to_sym
8
- @modify_spec = modify_spec.symbolize_keys
10
+ @modify_spec = modify_spec || {}.with_indifferent_access
11
+ @spec = nil
9
12
  end
10
13
 
11
14
  def new_connection
@@ -22,20 +25,44 @@ module FreshConnection
22
25
  @spec ||= build_spec
23
26
  end
24
27
 
28
+ # when building a spec from envars, there may be no database.yml file, so
29
+ # be careful to avoid implicit dependency on it or derived contents.
30
+
25
31
  def build_spec
26
- config = ar_spec.config.symbolize_keys
27
- group_config = config[@group]
32
+ url = database_group_url(@group.to_s)
33
+ if url
34
+ build_group_spec_from_url(url)
35
+ else
36
+ build_spec_from_config
37
+ end
38
+ end
39
+
40
+ def database_group_url(group)
41
+ ENV['DATABASE_' + group.upcase + '_URL']
42
+ end
43
+
44
+ def build_group_spec_from_url(url)
45
+ config = ar_spec.config.with_indifferent_access
46
+ spec = build_spec_from_url(url)
47
+ group_config = (config[@group] ||= {}.with_indifferent_access)
48
+ config.merge(group_config).merge(spec).merge(@modify_spec)
49
+ end
50
+
51
+ def build_spec_from_url(url)
52
+ ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(url).to_hash
53
+ end
28
54
 
29
- # provide backward compatibility for older :slave usage
30
- if !group_config && @group == :replica && config.key?(:slave)
55
+ def build_spec_from_config
56
+ config = ar_spec.config.with_indifferent_access
57
+ group_config = config[@group] || {}.with_indifferent_access
58
+
59
+ if group_config.size == 0 && @group == :replica && config.key?(:slave)
60
+ # provide backward-compatibility with :slave profile
31
61
  ActiveSupport::Deprecation.warn(
32
- "'slave' in database.yml is deprecated and will ignored from version 2.4.0. use 'replica' insted."
62
+ "'slave' in database.yml is deprecated and will ignored from version 2.4.0. use 'replica' instead."
33
63
  )
34
- group_config = config[:slave]
64
+ group_config = (config[:slave] || {}).with_indifferent_access
35
65
  end
36
-
37
- group_config = (group_config || {}).symbolize_keys
38
-
39
66
  config.merge(group_config).merge(@modify_spec)
40
67
  end
41
68
 
@@ -25,7 +25,7 @@ module FreshConnection
25
25
  all.manage_access(false, &block)
26
26
  end
27
27
 
28
- def establish_fresh_connection(replica_group = nil)
28
+ def establish_fresh_connection(replica_group = "replica")
29
29
  replica_connection_handler.establish_connection(name, replica_group)
30
30
  end
31
31
 
@@ -35,7 +35,7 @@ module FreshConnection
35
35
 
36
36
  def slave_connection
37
37
  ActiveSupport::Deprecation.warn(
38
- "'slave_connection' is deprecated and will removed from version 2.4.0. use 'replica_connection' insted."
38
+ "'slave_connection' is deprecated and will removed from version 2.4.0. use 'replica_connection' instead."
39
39
  )
40
40
 
41
41
  replica_connection
@@ -47,7 +47,7 @@ module FreshConnection
47
47
 
48
48
  def clear_all_slave_connections!
49
49
  ActiveSupport::Deprecation.warn(
50
- "'clear_all_slave_connections!' is deprecated and will removed from version 2.4.0. use 'clear_all_replica_connections!' insted."
50
+ "'clear_all_slave_connections!' is deprecated and will removed from version 2.4.0. use 'clear_all_replica_connections!' instead."
51
51
  )
52
52
 
53
53
  clear_all_replica_connections!
@@ -68,7 +68,7 @@ module FreshConnection
68
68
 
69
69
  def slave_connection_put_aside!
70
70
  ActiveSupport::Deprecation.warn(
71
- "'slave_connection_put_aside!' is deprecated and will removed from version 2.4.0. use 'replica_connection_put_aside!' insted."
71
+ "'slave_connection_put_aside!' is deprecated and will removed from version 2.4.0. use 'replica_connection_put_aside!' instead."
72
72
  )
73
73
 
74
74
  replica_connection_put_aside!
@@ -80,7 +80,7 @@ module FreshConnection
80
80
 
81
81
  def slave_connection_recovery?
82
82
  ActiveSupport::Deprecation.warn(
83
- "'slave_connection_recovery?' is deprecated and will removed from version 2.4.0. use 'replica_connection_recovery?' insted."
83
+ "'slave_connection_recovery?' is deprecated and will removed from version 2.4.0. use 'replica_connection_recovery?' instead."
84
84
  )
85
85
 
86
86
  replica_connection_recovery?
@@ -92,7 +92,7 @@ module FreshConnection
92
92
 
93
93
  def slave_group
94
94
  ActiveSupport::Deprecation.warn(
95
- "'slave_connection_recovery?' is deprecated and will removed from version 2.4.0. use 'replica_connection_recovery?' insted."
95
+ "'slave_connection_recovery?' is deprecated and will removed from version 2.4.0. use 'replica_connection_recovery?' instead."
96
96
  )
97
97
 
98
98
  replica_group
@@ -60,7 +60,7 @@ module FreshConnection
60
60
 
61
61
  def enable_slave_access
62
62
  ActiveSupport::Deprecation.warn(
63
- "'enable_slave_access' is deprecated and will removed from version 2.4.0. use 'enable_replica_access' insted."
63
+ "'enable_slave_access' is deprecated and will removed from version 2.4.0. use 'enable_replica_access' instead."
64
64
  )
65
65
 
66
66
  enable_replica_access
@@ -3,15 +3,17 @@ require 'concurrent'
3
3
  module FreshConnection
4
4
  class ReplicaConnectionHandler
5
5
  def initialize
6
+ @replica_group_to_pool = Concurrent::Map.new
6
7
  @class_to_pool = Concurrent::Map.new
7
8
  end
8
9
 
9
10
  def establish_connection(name, replica_group)
10
- if cm = class_to_pool[name]
11
+ if cm = @class_to_pool[name]
11
12
  cm.put_aside!
13
+ @class_to_pool.delete(name)
12
14
  end
13
15
 
14
- class_to_pool[name] = FreshConnection.connection_manager.new(replica_group)
16
+ @replica_group_to_pool[name] = replica_group
15
17
  end
16
18
 
17
19
  def connection(klass)
@@ -41,20 +43,23 @@ module FreshConnection
41
43
  private
42
44
 
43
45
  def all_connection_managers
44
- class_to_pool.each_value do |connection_manager|
46
+ @class_to_pool.each_value do |connection_manager|
45
47
  yield(connection_manager)
46
48
  end
47
49
  end
48
50
 
49
51
  def detect_connection_manager(klass)
50
- c = class_to_pool[klass.name]
52
+ c = class_to_pool(klass.name)
51
53
  return c if c
52
54
  return nil if ActiveRecord::Base == klass
53
55
  detect_connection_manager(klass.superclass)
54
56
  end
55
57
 
56
- def class_to_pool
57
- @class_to_pool
58
+ def class_to_pool(name)
59
+ return @class_to_pool[name] if @class_to_pool.key?(name)
60
+ g = @replica_group_to_pool[name]
61
+ return nil unless g
62
+ @class_to_pool[name] = FreshConnection.connection_manager.new(g)
58
63
  end
59
64
  end
60
65
  end
@@ -1,4 +1,4 @@
1
1
  module FreshConnection
2
- VERSION = "2.3.0"
2
+ VERSION = "2.3.1"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fresh_connection
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tsukasa OISHI
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-18 00:00:00.000000000 Z
11
+ date: 2017-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord