ar_mysql_flexmaster 0.2.1 → 0.2.2

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.
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
12
12
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
13
  gem.name = "ar_mysql_flexmaster"
14
14
  gem.require_paths = ["lib"]
15
- gem.version = "0.2.1"
15
+ gem.version = "0.2.2"
16
16
 
17
17
  gem.add_runtime_dependency("mysql2")
18
18
  gem.add_runtime_dependency("activerecord")
@@ -25,6 +25,8 @@ module ActiveRecord
25
25
  module ConnectionAdapters
26
26
  class MysqlFlexmasterAdapter < Mysql2Adapter
27
27
  class NoActiveMasterException < Exception; end
28
+ class TooManyMastersException < Exception; end
29
+ class NoServerAvailableException < Exception; end
28
30
 
29
31
  CHECK_EVERY_N_SELECTS = 10
30
32
  DEFAULT_CONNECT_TIMEOUT = 5
@@ -36,8 +38,10 @@ module ActiveRecord
36
38
  @is_master = !config[:slave]
37
39
  @tx_hold_timeout = @config[:tx_hold_timeout] || DEFAULT_TX_HOLD_TIMEOUT
38
40
  @connection_timeout = @config[:connection_timeout] || DEFAULT_CONNECT_TIMEOUT
41
+
39
42
  connection = find_correct_host
40
- raise NoActiveMasterException unless connection
43
+
44
+ raise_no_server_available! unless connection
41
45
  super(connection, logger, [], config)
42
46
  end
43
47
 
@@ -69,7 +73,26 @@ module ActiveRecord
69
73
  raise NoActiveMasterException unless @connection
70
74
  end
71
75
 
76
+ def raise_no_server_available!
77
+ raise NoServerAvailableException.new(errors_to_message)
78
+ end
79
+
80
+ def collected_errors
81
+ @collected_errors ||= []
82
+ end
83
+
84
+ def clear_collected_errors!
85
+ @collected_errors = []
86
+ end
87
+
88
+ def errors_to_message
89
+ "Errors encountered while trying #{@config[:hosts].inspect}: " +
90
+ collected_errors.map { |e| "#{e.class.name}: #{e.message}" }.uniq.join(",")
91
+ end
92
+
72
93
  def refind_correct_host(tries = nil, sleep_interval = nil)
94
+ clear_collected_errors!
95
+
73
96
  tries ||= @tx_hold_timeout.to_f / 0.1
74
97
  sleep_interval ||= 0.1
75
98
  tries.to_i.times do
@@ -80,7 +103,7 @@ module ActiveRecord
80
103
  end
81
104
  sleep(sleep_interval)
82
105
  end
83
- raise NoActiveMasterException
106
+ raise_no_server_available!
84
107
  end
85
108
 
86
109
  def hosts_and_ports
@@ -106,6 +129,12 @@ module ActiveRecord
106
129
  else
107
130
  # nothing read-write, or too many read-write
108
131
  # (should we manually close the connections?)
132
+ if correct_cxs.size > 1
133
+ collected_errors << TooManyMastersException.new("found #{correct_cxs.size} read-write servers")
134
+ else
135
+ collected_errors << NoActiveMasterException.new("no read-write servers found")
136
+ end
137
+
109
138
  chosen_cx = nil
110
139
  end
111
140
  else
@@ -128,8 +157,12 @@ module ActiveRecord
128
157
  cx.query_options.merge!(:as => :array)
129
158
  end
130
159
  end
131
- rescue Mysql2::Error
132
- rescue Timeout::Error
160
+ rescue Mysql2::Error => e
161
+ collected_errors << e
162
+ nil
163
+ rescue Timeout::Error => e
164
+ collected_errors << e
165
+ nil
133
166
  end
134
167
  end
135
168
 
@@ -38,13 +38,15 @@ end
38
38
  # $mysql_master and $mysql_slave are separate references to the master and slave that we
39
39
  # use to send control-channel commands on
40
40
 
41
+ $original_master_port = $mysql_master.port
42
+
41
43
  class TestArFlexmaster < Test::Unit::TestCase
42
44
  def setup
43
45
  ActiveRecord::Base.establish_connection("test")
44
46
 
45
- $mysql_master.set_rw(true)
46
- $mysql_slave.set_rw(false)
47
- $mysql_slave_2.set_rw(false)
47
+ $mysql_master.set_rw(true) if $mysql_master
48
+ $mysql_slave.set_rw(false) if $mysql_slave
49
+ $mysql_slave_2.set_rw(false) if $mysql_slave_2
48
50
  end
49
51
 
50
52
  def test_should_raise_without_a_rw_master
@@ -52,9 +54,11 @@ class TestArFlexmaster < Test::Unit::TestCase
52
54
  m.set_rw(false)
53
55
  end
54
56
 
55
- assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoActiveMasterException) do
57
+ e = assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoServerAvailableException) do
56
58
  ActiveRecord::Base.connection
57
59
  end
60
+
61
+ assert e.message =~ /NoActiveMasterException/
58
62
  end
59
63
 
60
64
  def test_should_select_the_master_on_boot
@@ -66,7 +70,7 @@ class TestArFlexmaster < Test::Unit::TestCase
66
70
 
67
71
  $mysql_master.set_rw(false)
68
72
  start_time = Time.now.to_i
69
- assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoActiveMasterException) do
73
+ e = assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoServerAvailableException) do
70
74
  User.create(:name => "foo")
71
75
  end
72
76
  end_time = Time.now.to_i
@@ -150,7 +154,10 @@ class TestArFlexmaster < Test::Unit::TestCase
150
154
 
151
155
  def test_yyy_shooting_the_master_in_the_head
152
156
  User.create!
153
- Process.kill("TERM", $mysql_master.pid)
157
+
158
+ $mysql_master.kill!
159
+ $mysql_master = nil
160
+
154
161
  sleep 1
155
162
  $mysql_slave.set_rw(true)
156
163
  User.connection.reconnect!
@@ -163,7 +170,10 @@ class TestArFlexmaster < Test::Unit::TestCase
163
170
  # note that by the time this test runs, the 'yyy' test has already killed the master
164
171
  def test_zzz_shooting_the_other_slave_in_the_head
165
172
  $mysql_slave.set_rw(true)
173
+
166
174
  $mysql_slave_2.kill!
175
+ $mysql_slave_2 = nil
176
+
167
177
  UserSlave.connection.reconnect!
168
178
  assert port_for_class(UserSlave) == $mysql_slave.port
169
179
  end
@@ -177,6 +187,6 @@ class TestArFlexmaster < Test::Unit::TestCase
177
187
 
178
188
  def main_connection_is_original_master?
179
189
  port = port_for_class(ActiveRecord::Base)
180
- port == $mysql_master.port
190
+ port == $original_master_port
181
191
  end
182
192
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar_mysql_flexmaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-18 00:00:00.000000000 Z
12
+ date: 2013-03-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mysql2
@@ -140,18 +140,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
140
  - - ! '>='
141
141
  - !ruby/object:Gem::Version
142
142
  version: '0'
143
- segments:
144
- - 0
145
- hash: -961261778755012131
146
143
  required_rubygems_version: !ruby/object:Gem::Requirement
147
144
  none: false
148
145
  requirements:
149
146
  - - ! '>='
150
147
  - !ruby/object:Gem::Version
151
148
  version: '0'
152
- segments:
153
- - 0
154
- hash: -961261778755012131
155
149
  requirements: []
156
150
  rubyforge_project:
157
151
  rubygems_version: 1.8.24