standby 5.0.0 → 5.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: 0b43e6971bad583281f150be7a768115af32883b72bdd42c16ee9b885c33b070
4
- data.tar.gz: a6574d223d15071d3143dadcf3977edb82227c5b5455a55129e5887c4c097e16
3
+ metadata.gz: ed313fd2c207aef137a574816b7574d6614d5c2446f2d733aa7d08d2a40b6382
4
+ data.tar.gz: cda7f21a3cf9aa71c84da0cf8e985e965bd78fde3a21b5e57a8902a0e4b581a4
5
5
  SHA512:
6
- metadata.gz: 5298e4882873365eb18a25a92e393547c9587d40e5acd70cdd25c87503d1d77ba713dab54ec826c4a675958c2aa2beb6dd31dd61da105c679712d884f981f9b9
7
- data.tar.gz: 13cd75e347a2abbaa974e1f761422d6f2ad33d0cacd01c462a9e8d9e61f66febb47f87b6edcef89aefe3ec57c82b80291f79d83c50bb7c49b1139917d565e41c
6
+ metadata.gz: 3e9d7d67ea19465e263e36a7c6318e9f4de15b6c9f53dd1a0e51e6782b1118c2c0e3352b213c687b44ffc2da5d87cc5aa9a270b7e3cea2b3f64b86be4d9d74e5
7
+ data.tar.gz: 4d07f9692a78f4777814282ee120d9ac6df6ad0e723555758f1bb29062082158460728579c2666e3def498a8eaead6b29b4bc344beab76c9d50f6f41a62c5856
@@ -10,6 +10,7 @@ jobs:
10
10
  - "2.7"
11
11
  rails_version:
12
12
  - "7.0"
13
+ - "6.1"
13
14
  - "5.2"
14
15
  runs-on: ubuntu-latest
15
16
  env:
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- # require 'bundler/gem_tasks'
1
+ require 'bundler/gem_helper'
2
2
  Bundler::GemHelper.install_tasks(name: 'standby')
3
3
 
4
4
  # RSpec
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '~> 6.1'
4
+ gem 'sqlite3', '~> 1.4'
5
+
6
+ # Rails 6.1 compat with Ruby 3.4+ (these were removed from default gems)
7
+ gem 'logger'
8
+ gem 'mutex_m'
9
+ gem 'bigdecimal'
10
+ gem 'base64'
11
+ gem 'drb'
12
+
13
+ gemspec name: 'standby', path: '../'
@@ -1,8 +1,18 @@
1
1
  module ActiveRecord
2
2
  class Base
3
3
  class << self
4
+ alias_method :connection_pool_without_standby, :connection_pool
4
5
  alias_method :connection_without_standby, :connection
5
6
 
7
+ def connection_pool
8
+ case Thread.current[:_standby]
9
+ when :primary, NilClass
10
+ connection_pool_without_standby
11
+ else
12
+ Standby.connection_holder(Thread.current[:_standby]).connection_pool_without_standby
13
+ end
14
+ end
15
+
6
16
  def connection
7
17
  case Thread.current[:_standby]
8
18
  when :primary, NilClass
@@ -6,7 +6,8 @@ module Standby
6
6
  # for delayed activation
7
7
  def activate(target)
8
8
  env_name = "#{ActiveRecord::ConnectionHandling::RAILS_ENV.call}_#{target}"
9
- if Standby.version_gte?('7.0')
9
+ # Rails 6.1+ exposes DatabaseConfigurations helpers; older versions still use hash access.
10
+ if ActiveRecord::Base.configurations.respond_to?(:find_db_config)
10
11
  spec = ActiveRecord::Base.configurations.find_db_config(env_name)&.configuration_hash
11
12
  else
12
13
  spec = ActiveRecord::Base.configurations[env_name]
@@ -21,14 +22,16 @@ module Standby
21
22
  class << self
22
23
  def connection_holder(target)
23
24
  klass_name = "Standby#{target.to_s.camelize}ConnectionHolder"
24
- standby_connections[klass_name] ||= begin
25
- klass = Class.new(Standby::ConnectionHolder) do
26
- self.abstract_class = true
25
+ standby_connections[klass_name] || standby_connections_mutex.synchronize do
26
+ standby_connections[klass_name] ||= begin
27
+ klass = Class.new(Standby::ConnectionHolder) do
28
+ self.abstract_class = true
29
+ end
30
+ Object.const_set(klass_name, klass)
31
+ klass.activate(target)
32
+ klass
27
33
  end
28
- Object.const_set(klass_name, klass)
29
- klass.activate(target)
30
- klass
31
34
  end
32
35
  end
33
36
  end
34
- end
37
+ end
@@ -1,5 +1,5 @@
1
1
  module Standby
2
- VERSION = '5.0.0'
2
+ VERSION = '5.1.0'
3
3
 
4
4
  class << self
5
5
  def version_gte?(version)
data/lib/standby.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'logger'
1
2
  require 'active_record'
2
3
  require 'standby/version'
3
4
  require 'standby/base'
@@ -10,11 +11,18 @@ require 'standby/active_record/relation'
10
11
  require 'standby/active_record/log_subscriber'
11
12
 
12
13
  module Standby
14
+ @standby_connections = {}
15
+ @standby_connections_mutex = Mutex.new
16
+
13
17
  class << self
14
18
  attr_accessor :disabled
15
19
 
16
20
  def standby_connections
17
- @standby_connections ||= {}
21
+ @standby_connections
22
+ end
23
+
24
+ def standby_connections_mutex
25
+ @standby_connections_mutex
18
26
  end
19
27
 
20
28
  def on_standby(name = :null_state, &block)
@@ -3,8 +3,9 @@ require 'spec_helper'
3
3
  describe 'configuration' do
4
4
  before do
5
5
  # Backup connection and configs
6
- @backup_conn = Standby.instance_variable_get :@standby_connections
7
- if Standby.version_gte?('7.0')
6
+ @backup_conn = (Standby.instance_variable_get(:@standby_connections) || {}).dup
7
+ # Rails 6.1+ wraps configurations in ActiveRecord::DatabaseConfigurations.
8
+ if ActiveRecord::Base.configurations.respond_to?(:configs_for)
8
9
  @backup_config = ActiveRecord::Base.configurations.configs_for.map do |config|
9
10
  [config.env_name, config.configuration_hash]
10
11
  end.to_h
@@ -26,7 +27,8 @@ describe 'configuration' do
26
27
  end
27
28
 
28
29
  it 'raises error if standby configuration not specified' do
29
- if Standby.version_gte?('7.0')
30
+ # Rails 6.1+ no longer supports mutating configurations via hash-style access.
31
+ if ActiveRecord::Base.configurations.respond_to?(:configs_for)
30
32
  ActiveRecord::Base.configurations = @backup_config.merge({ 'test_standby' => {} })
31
33
  else
32
34
  ActiveRecord::Base.configurations['test_standby'] = nil
@@ -36,7 +38,8 @@ describe 'configuration' do
36
38
  end
37
39
 
38
40
  it 'connects to primary if standby configuration is disabled' do
39
- if Standby.version_gte?('7.0')
41
+ # Rails 6.1+ no longer supports mutating configurations via hash-style access.
42
+ if ActiveRecord::Base.configurations.respond_to?(:configs_for)
40
43
  ActiveRecord::Base.configurations = @backup_config.merge({ 'test_standby' => {} })
41
44
  else
42
45
  ActiveRecord::Base.configurations['test_standby'] = nil
@@ -45,4 +48,35 @@ describe 'configuration' do
45
48
 
46
49
  expect(Standby.on_standby { User.count }).to be 2
47
50
  end
51
+
52
+ it 'initializes a standby connection holder once under contention' do
53
+ entered_activate = Queue.new
54
+ release_activate = Queue.new
55
+ call_count = 0
56
+
57
+ allow(Standby::ConnectionHolder).to receive(:activate).and_wrap_original do |original, target|
58
+ call_count += 1
59
+ if call_count == 1
60
+ entered_activate << true
61
+ release_activate.pop
62
+ end
63
+
64
+ original.call(target)
65
+ end
66
+
67
+ t1 = Thread.new { Standby.connection_holder(:standby) }
68
+ entered_activate.pop
69
+
70
+ t2 = Thread.new { Standby.connection_holder(:standby) }
71
+
72
+ expect(t2.join(0.1)).to be_nil
73
+ expect(call_count).to eq(1)
74
+
75
+ release_activate << true
76
+
77
+ [t1, t2].each(&:join)
78
+
79
+ expect(Standby.connection_holder(:standby).name).to eq('StandbyStandbyConnectionHolder')
80
+ expect(call_count).to eq(1)
81
+ end
48
82
  end
data/spec/spec_helper.rb CHANGED
@@ -52,7 +52,11 @@ class Seeder
52
52
  end
53
53
 
54
54
  def connect(env)
55
+ ActiveRecord::Base.connection_pool.disconnect! if ActiveRecord::Base.connected?
55
56
  ActiveRecord::Base.establish_connection(env)
57
+ return unless ActiveRecord::Base.connection.adapter_name == 'SQLite'
58
+
59
+ ActiveRecord::Base.connection.execute('PRAGMA journal_mode=DELETE')
56
60
  end
57
61
  end
58
62
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standby
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenn Ejima
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-11-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activerecord
@@ -89,6 +88,7 @@ files:
89
88
  - bin/console
90
89
  - gemfiles/rails4.2.gemfile
91
90
  - gemfiles/rails5.2.gemfile
91
+ - gemfiles/rails6.1.gemfile
92
92
  - gemfiles/rails7.0.gemfile
93
93
  - lib/standby.rb
94
94
  - lib/standby/active_record/base.rb
@@ -108,7 +108,6 @@ files:
108
108
  homepage: https://github.com/kenn/standby
109
109
  licenses: []
110
110
  metadata: {}
111
- post_install_message:
112
111
  rdoc_options: []
113
112
  require_paths:
114
113
  - lib
@@ -123,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
122
  - !ruby/object:Gem::Version
124
123
  version: '0'
125
124
  requirements: []
126
- rubygems_version: 3.1.4
127
- signing_key:
125
+ rubygems_version: 3.6.9
128
126
  specification_version: 4
129
127
  summary: Read from stand-by databases for ActiveRecord
130
128
  test_files: