ar_mysql_flexmaster 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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