lhm-shopify 3.5.1 → 3.5.5

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.
data/lib/lhm/sql_retry.rb CHANGED
@@ -18,6 +18,12 @@ module Lhm
18
18
  class SqlRetry
19
19
  RECONNECT_SUCCESSFUL_MESSAGE = "LHM successfully reconnected to initial host:"
20
20
  CLOUDSQL_VERSION_COMMENT = "(Google)"
21
+ # Will retry for 120 seconds (approximately, since connecting takes time).
22
+ RECONNECT_RETRY_MAX_ITERATION = 120
23
+ RECONNECT_RETRY_INTERVAL = 1
24
+ # Will abort the LHM if it had to reconnect more than 25 times in a single run (indicator that there might be
25
+ # something wrong with the network and would be better to run the LHM at a later time).
26
+ RECONNECTION_MAXIMUM = 25
21
27
 
22
28
  MYSQL_VAR_NAMES = {
23
29
  hostname: "@@global.hostname",
@@ -25,30 +31,24 @@ module Lhm
25
31
  version_comment: "@@version_comment",
26
32
  }
27
33
 
28
- # This internal error is used to trigger retries from the parent Retriable.retriable in #with_retries
29
- class ReconnectToHostSuccessful < Lhm::Error; end
30
-
31
- def initialize(connection, options: {}, reconnect_with_consistent_host: true)
34
+ def initialize(connection, retry_options: {}, reconnect_with_consistent_host: false)
32
35
  @connection = connection
33
- @log_prefix = options.delete(:log_prefix)
34
- @global_retry_config = default_retry_config.dup.merge!(options)
35
- if (@reconnect_with_consistent_host = reconnect_with_consistent_host)
36
- @initial_hostname = hostname
37
- @initial_server_id = server_id
38
- end
36
+ self.retry_config = retry_options
37
+ self.reconnect_with_consistent_host = reconnect_with_consistent_host
39
38
  end
40
39
 
41
40
  # Complete explanation of algorithm: https://github.com/Shopify/lhm/pull/112
42
- def with_retries(retry_config = {})
43
- @log_prefix = retry_config.delete(:log_prefix)
41
+ def with_retries(log_prefix: nil)
42
+ @log_prefix = log_prefix || "" # No prefix. Just logs
44
43
 
45
- retry_config = @global_retry_config.dup.merge!(retry_config)
44
+ # Amount of time LHM had to reconnect. Aborting if more than RECONNECTION_MAXIMUM
45
+ reconnection_counter = 0
46
46
 
47
- Retriable.retriable(retry_config) do
47
+ Retriable.retriable(@retry_config) do
48
48
  # Using begin -> rescue -> end for Ruby 2.4 compatibility
49
49
  begin
50
50
  if @reconnect_with_consistent_host
51
- raise Lhm::Error.new("Could not reconnected to initial MySQL host. Aborting to avoid data-loss") unless same_host_as_initial?
51
+ raise Lhm::Error.new("MySQL host has changed since the start of the LHM. Aborting to avoid data-loss") unless same_host_as_initial?
52
52
  end
53
53
 
54
54
  yield(@connection)
@@ -57,13 +57,36 @@ module Lhm
57
57
  # The error will be raised the connection is still active (i.e. no need to reconnect) or if the connection is
58
58
  # dead (i.e. not active) and @reconnect_with_host is false (i.e. instructed not to reconnect)
59
59
  raise e if @connection.active? || (!@connection.active? && !@reconnect_with_consistent_host)
60
- reconnect_with_host_check! if @reconnect_with_consistent_host
60
+
61
+ # Lhm could be stuck in a weird state where it loses connection, reconnects and re looses-connection instantly
62
+ # after, creating an infinite loop (because of the usage of `retry`). Hence, abort after 25 reconnections
63
+ raise Lhm::Error.new("LHM reached host reconnection max of #{RECONNECTION_MAXIMUM} times. " \
64
+ "Please try again later.") if reconnection_counter > RECONNECTION_MAXIMUM
65
+
66
+ reconnection_counter += 1
67
+ if reconnect_with_host_check!
68
+ retry
69
+ else
70
+ raise Lhm::Error.new("LHM tried the reconnection procedure but failed. Aborting")
71
+ end
61
72
  end
62
73
  end
63
74
  end
64
75
 
65
- attr_reader :global_retry_config
66
- attr_accessor :reconnect_with_consistent_host
76
+ # Both attributes will have defined setters
77
+ attr_reader :retry_config, :reconnect_with_consistent_host
78
+ attr_accessor :connection
79
+
80
+ def retry_config=(retry_options)
81
+ @retry_config = default_retry_config.dup.merge!(retry_options)
82
+ end
83
+
84
+ def reconnect_with_consistent_host=(reconnect)
85
+ if (@reconnect_with_consistent_host = reconnect)
86
+ @initial_hostname = hostname
87
+ @initial_server_id = server_id
88
+ end
89
+ end
67
90
 
68
91
  private
69
92
 
@@ -99,34 +122,32 @@ module Lhm
99
122
 
100
123
  def reconnect_with_host_check!
101
124
  log_with_prefix("Lost connection to MySQL, will retry to connect to same host")
102
- begin
103
- Retriable.retriable(host_retry_config) do
125
+
126
+ RECONNECT_RETRY_MAX_ITERATION.times do
127
+ begin
128
+ sleep(RECONNECT_RETRY_INTERVAL)
129
+
104
130
  # tries to reconnect. On failure will trigger a retry
105
131
  @connection.reconnect!
106
132
 
107
133
  if same_host_as_initial?
108
134
  # This is not an actual error, but controlled way to get the parent `Retriable.retriable` to retry
109
135
  # the statement that failed (since the Retriable gem only retries on errors).
110
- raise ReconnectToHostSuccessful.new("LHM successfully reconnected to initial host: #{@initial_hostname} (server_id: #{@initial_server_id})")
136
+ log_with_prefix("LHM successfully reconnected to initial host: #{@initial_hostname} (server_id: #{@initial_server_id})")
137
+ return true
111
138
  else
112
139
  # New Master --> abort LHM (reconnecting will not change anything)
113
- raise Lhm::Error.new("Reconnected to wrong host. Started migration on: #{@initial_hostname} (server_id: #{@initial_server_id}), but reconnected to: #{hostname} (server_id: #{@initial_server_id}).")
140
+ log_with_prefix("Reconnected to wrong host. Started migration on: #{@initial_hostname} (server_id: #{@initial_server_id}), but reconnected to: #{hostname} (server_id: #{server_id}).", :error)
141
+ return false
114
142
  end
143
+ rescue StandardError => e
144
+ # Retry if ActiveRecord cannot reach host
145
+ next if /Lost connection to MySQL server at 'reading initial communication packet'/ === e.message
146
+ log_with_prefix("Encountered error: [#{e.class}] #{e.message}. Will stop reconnection procedure.", :info)
147
+ return false
115
148
  end
116
- rescue StandardError => e
117
- # The parent Retriable.retriable is configured to retry if it encounters an error with the success message.
118
- # Therefore, if the connection is re-established successfully AND the host is the same, LHM can retry the query
119
- # that originally failed.
120
- raise e if reconnect_successful?(e)
121
- # If the connection was not successful, the parent retriable will raise any error that originated from the
122
- # `@connection.reconnect!`
123
- # Therefore, this error will cause the LHM to abort
124
- raise Lhm::Error.new("LHM tried the reconnection procedure but failed. Latest error: #{e.message}")
125
149
  end
126
- end
127
-
128
- def reconnect_successful?(e)
129
- e.is_a?(ReconnectToHostSuccessful)
150
+ false
130
151
  end
131
152
 
132
153
  # For a full list of configuration options see https://github.com/kamui/retriable
@@ -143,9 +164,6 @@ module Lhm
143
164
  /Unknown MySQL server host/,
144
165
  /connection is locked to hostgroup/,
145
166
  /The MySQL server is running with the --read-only option so it cannot execute this statement/,
146
- ],
147
- ReconnectToHostSuccessful => [
148
- /#{RECONNECT_SUCCESSFUL_MESSAGE}/
149
167
  ]
150
168
  },
151
169
  multiplier: 1, # each successive interval grows by this factor
@@ -153,28 +171,6 @@ module Lhm
153
171
  tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
154
172
  rand_factor: 0, # percentage to randomize the next retry interval time
155
173
  max_elapsed_time: Float::INFINITY, # max total time in seconds that code is allowed to keep being retried
156
- on_retry: Proc.new do |exception, try_number, total_elapsed_time, next_interval|
157
- if reconnect_successful?(exception)
158
- log_with_prefix("#{exception.message} -- triggering retry", :info)
159
- else
160
- log_with_prefix("#{exception.class}: '#{exception.message}' - #{try_number} tries in #{total_elapsed_time} seconds and #{next_interval} seconds until the next try.", :error)
161
- end
162
- end
163
- }.freeze
164
- end
165
-
166
- def host_retry_config
167
- {
168
- on: {
169
- StandardError => [
170
- /Lost connection to MySQL server at 'reading initial communication packet'/
171
- ]
172
- },
173
- multiplier: 1, # each successive interval grows by this factor
174
- base_interval: 0.25, # the initial interval in seconds between tries.
175
- tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
176
- rand_factor: 0, # percentage to randomize the next retry interval time
177
- max_elapsed_time: Float::INFINITY, # max total time in seconds that code is allowed to keep being retried
178
174
  on_retry: Proc.new do |exception, try_number, total_elapsed_time, next_interval|
179
175
  log_with_prefix("#{exception.class}: '#{exception.message}' - #{try_number} tries in #{total_elapsed_time} seconds and #{next_interval} seconds until the next try.", :error)
180
176
  end
data/lib/lhm/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Schmidt
3
3
 
4
4
  module Lhm
5
- VERSION = '3.5.1'
5
+ VERSION = '3.5.5'
6
6
  end
data/lib/lhm.rb CHANGED
@@ -28,7 +28,7 @@ module Lhm
28
28
  extend Throttler
29
29
  extend self
30
30
 
31
- DEFAULT_LOGGER_OPTIONS = { level: Logger::INFO, file: STDOUT }
31
+ DEFAULT_LOGGER_OPTIONS = { level: Logger::INFO, file: STDOUT }
32
32
 
33
33
  # Alters a table with the changes described in the block
34
34
  #
@@ -46,15 +46,19 @@ module Lhm
46
46
  # Use atomic switch to rename tables (defaults to: true)
47
47
  # If using a version of mysql affected by atomic switch bug, LHM forces user
48
48
  # to set this option (see SqlHelper#supports_atomic_switch?)
49
+ # @option options [Boolean] :reconnect_with_consistent_host
50
+ # Active / Deactivate ProxySQL-aware reconnection procedure (default to: false)
49
51
  # @yield [Migrator] Yielded Migrator object records the changes
50
52
  # @return [Boolean] Returns true if the migration finishes
51
53
  # @raise [Error] Raises Lhm::Error in case of a error and aborts the migration
52
54
  def change_table(table_name, options = {}, &block)
53
- origin = Table.parse(table_name, connection)
54
- invoker = Invoker.new(origin, connection)
55
- block.call(invoker.migrator)
56
- invoker.run(options)
57
- true
55
+ with_flags(options) do
56
+ origin = Table.parse(table_name, connection)
57
+ invoker = Invoker.new(origin, connection)
58
+ block.call(invoker.migrator)
59
+ invoker.run(options)
60
+ true
61
+ end
58
62
  end
59
63
 
60
64
  # Cleanup tables and triggers
@@ -86,26 +90,16 @@ module Lhm
86
90
  # Setups DB connection
87
91
  #
88
92
  # @param [ActiveRecord::Base] connection ActiveRecord Connection
89
- # @param [Hash] connection_options Optional options (defaults to: empty hash)
90
- # @option connection_options [Boolean] :reconnect_with_consistent_host
91
- # Active / Deactivate ProxySQL-aware reconnection procedure (default to: false)
92
- def setup(connection, connection_options = {})
93
- @@connection = Connection.new(connection: connection, options: connection_options)
93
+ def setup(connection)
94
+ @@connection = Connection.new(connection: connection)
94
95
  end
95
96
 
96
- # Setups DB connection
97
- #
98
- # @param [Hash] connection_options Optional options (defaults to: empty hash)
99
- # @option connection_options [Boolean] :reconnect_with_consistent_host
100
- # Active / Deactivate ProxySQL-aware reconnection procedure (default to: false)
101
- def connection(connection_options = nil)
102
- if @@connection.nil?
103
- raise 'Please call Lhm.setup' unless defined?(ActiveRecord)
104
- @@connection = Connection.new(connection: ActiveRecord::Base.connection, options: connection_options || {})
105
- else
106
- @@connection.options = connection_options unless connection_options.nil?
107
- end
108
- @@connection
97
+ # Returns DB connection (or initializes it if not created yet)
98
+ def connection
99
+ @@connection ||= begin
100
+ raise 'Please call Lhm.setup' unless defined?(ActiveRecord)
101
+ @@connection = Connection.new(connection: ActiveRecord::Base.connection)
102
+ end
109
103
  end
110
104
 
111
105
  def self.logger=(new_logger)
@@ -147,4 +141,16 @@ module Lhm
147
141
  false
148
142
  end
149
143
  end
144
+
145
+ def with_flags(options)
146
+ old_flags = {
147
+ reconnect_with_consistent_host: Lhm.connection.reconnect_with_consistent_host,
148
+ }
149
+
150
+ Lhm.connection.reconnect_with_consistent_host = options[:reconnect_with_consistent_host] || false
151
+
152
+ yield
153
+ ensure
154
+ Lhm.connection.reconnect_with_consistent_host = old_flags[:reconnect_with_consistent_host]
155
+ end
150
156
  end
@@ -39,10 +39,15 @@ describe Lhm::AtomicSwitcher do
39
39
  .then
40
40
  .returns([["dummy"]]) # Matches initial host -> triggers retry
41
41
 
42
- connection = Lhm::Connection.new(connection: ar_connection, options: {reconnect_with_consistent_host: true})
42
+ connection = Lhm::Connection.new(connection: ar_connection, options: {
43
+ reconnect_with_consistent_host: true,
44
+ retriable: {
45
+ tries: 3,
46
+ base_interval: 0
47
+ }
48
+ })
43
49
 
44
-
45
- switcher = Lhm::AtomicSwitcher.new(@migration, connection, retriable: { tries: 3, base_interval: 0 })
50
+ switcher = Lhm::AtomicSwitcher.new(@migration, connection)
46
51
 
47
52
  assert switcher.run
48
53
 
@@ -58,20 +63,26 @@ describe Lhm::AtomicSwitcher do
58
63
  ar_connection.stubs(:data_source_exists?).returns(true)
59
64
  ar_connection.stubs(:active?).returns(true)
60
65
  ar_connection.stubs(:execute).returns([["dummy"]], [["dummy"]], [["dummy"]])
61
- .then
62
- .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
63
- .then
64
- .returns([["dummy"]]) # triggers retry 1
65
- .then
66
- .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
67
- .then
68
- .returns([["dummy"]]) # triggers retry 2
69
- .then
70
- .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.') # triggers retry 2
71
-
72
- connection = Lhm::Connection.new(connection: ar_connection, options: {reconnect_with_consistent_host: true})
73
-
74
- switcher = Lhm::AtomicSwitcher.new(@migration, connection, retriable: { tries: 2, base_interval: 0 })
66
+ .then
67
+ .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
68
+ .then
69
+ .returns([["dummy"]]) # triggers retry 1
70
+ .then
71
+ .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
72
+ .then
73
+ .returns([["dummy"]]) # triggers retry 2
74
+ .then
75
+ .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.') # triggers retry 2
76
+
77
+ connection = Lhm::Connection.new(connection: ar_connection, options: {
78
+ reconnect_with_consistent_host: true,
79
+ retriable: {
80
+ tries: 2,
81
+ base_interval: 0
82
+ }
83
+ })
84
+
85
+ switcher = Lhm::AtomicSwitcher.new(@migration, connection)
75
86
 
76
87
  assert_raises(ActiveRecord::StatementInvalid) { switcher.run }
77
88
  end
@@ -173,6 +173,9 @@ describe Lhm::Chunker do
173
173
  printer.expect(:notify, :return_value, [Integer, Integer])
174
174
  printer.expect(:end, :return_value, [])
175
175
 
176
+ Lhm::Throttler::Slave.any_instance.stubs(:slave_hosts).returns(['127.0.0.1'])
177
+ Lhm::Throttler::SlaveLag.any_instance.stubs(:master_slave_hosts).returns(['127.0.0.1'])
178
+
176
179
  Lhm::Chunker.new(
177
180
  @migration, connection, { throttler: Lhm::Throttler::SlaveLag.new(stride: 100), printer: printer }
178
181
  ).run
@@ -215,17 +218,16 @@ describe Lhm::Chunker do
215
218
  printer.expects(:verify)
216
219
  printer.expects(:end)
217
220
 
218
- throttler = Lhm::Throttler::SlaveLag.new(stride: 10, allowed_lag: 0)
221
+ Lhm::Throttler::Slave.any_instance.stubs(:slave_hosts).returns(['127.0.0.1'])
222
+ Lhm::Throttler::SlaveLag.any_instance.stubs(:master_slave_hosts).returns(['127.0.0.1'])
219
223
 
220
- def throttler.slave_hosts
221
- ['127.0.0.1']
222
- end
224
+ throttler = Lhm::Throttler::SlaveLag.new(stride: 10, allowed_lag: 0)
223
225
 
224
226
  if master_slave_mode?
225
227
  def throttler.slave_connection(slave)
226
228
  config = ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
227
229
  config[:host] = slave
228
- config[:port] = 3307
230
+ config[:port] = 33007
229
231
  ActiveRecord::Base.send('mysql2_connection', config)
230
232
  end
231
233
  end
@@ -62,18 +62,16 @@ module IntegrationHelper
62
62
  )
63
63
  end
64
64
 
65
- def connect_master_with_toxiproxy!(with_retry: false)
65
+ def connect_master_with_toxiproxy!
66
66
  connect!(
67
67
  '127.0.0.1',
68
68
  $db_config['master_toxic']['port'],
69
69
  $db_config['master_toxic']['user'],
70
- $db_config['master_toxic']['password'],
71
- with_retry)
70
+ $db_config['master_toxic']['password'])
72
71
  end
73
72
 
74
- def connect!(hostname, port, user, password, with_retry = false)
75
- adapter = ar_conn(hostname, port, user, password)
76
- Lhm.setup(adapter,{reconnect_with_consistent_host: with_retry})
73
+ def connect!(hostname, port, user, password)
74
+ Lhm.setup(ar_conn(hostname, port, user, password))
77
75
  unless defined?(@@cleaned_up)
78
76
  Lhm.cleanup(true)
79
77
  @@cleaned_up = true
@@ -592,7 +592,7 @@ describe Lhm do
592
592
  end
593
593
 
594
594
  it " should not try to reconnect if reconnect_with_consistent_host is not provided" do
595
- connect_master_with_toxiproxy!(with_retry: false)
595
+ connect_master_with_toxiproxy!
596
596
 
597
597
  table_create(:users)
598
598
  100.times { |n| execute("insert into users set reference = '#{ n }'") }
@@ -610,7 +610,7 @@ describe Lhm do
610
610
  end
611
611
 
612
612
  it "should reconnect if reconnect_with_consistent_host is true" do
613
- connect_master_with_toxiproxy!(with_retry: true)
613
+ connect_master_with_toxiproxy!
614
614
  mysql_disabled = false
615
615
 
616
616
  table_create(:users)
@@ -635,7 +635,7 @@ describe Lhm do
635
635
  method_added(:insert_and_return_count_of_rows_created)
636
636
  end
637
637
 
638
- Lhm.change_table(:users, :atomic_switch => false) do |t|
638
+ Lhm.change_table(:users, atomic_switch: false, reconnect_with_consistent_host: true) do |t|
639
639
  t.ddl("ALTER TABLE #{t.name} CHANGE id id bigint (20) NOT NULL")
640
640
  t.ddl("ALTER TABLE #{t.name} DROP PRIMARY KEY, ADD PRIMARY KEY (username, id)")
641
641
  t.ddl("ALTER TABLE #{t.name} ADD INDEX (id)")
@@ -645,7 +645,6 @@ describe Lhm do
645
645
  log_lines = @logs.string.split("\n")
646
646
 
647
647
  assert log_lines.one?{ |line| line.include?("Lost connection to MySQL, will retry to connect to same host")}
648
- assert log_lines.any?{ |line| line.include?("Lost connection to MySQL server at 'reading initial communication packet'")}
649
648
  assert log_lines.one?{ |line| line.include?("LHM successfully reconnected to initial host")}
650
649
  assert log_lines.one?{ |line| line.include?("100% complete")}
651
650
 
@@ -29,6 +29,6 @@ describe "ProxySQL integration" do
29
29
  port: "33005",
30
30
  )
31
31
 
32
- assert_equal conn.query("/*maintenance:lhm*/SELECT @@global.hostname as host").each.first["host"], "mysql-1"
32
+ assert_equal conn.query("SELECT @@global.hostname as host #{Lhm::ProxySQLHelper::ANNOTATION}").each.first["host"], "mysql-1"
33
33
  end
34
34
  end
@@ -55,7 +55,7 @@ describe Lhm::SqlRetry do
55
55
  it "successfully executes the SQL despite the errors encountered" do
56
56
  # Start a thread to retry, once the lock is held, execute the block
57
57
  @helper.with_waiting_lock do |waiting_connection|
58
- sql_retry = Lhm::SqlRetry.new(waiting_connection, options: {
58
+ sql_retry = Lhm::SqlRetry.new(waiting_connection, retry_options: {
59
59
  base_interval: 0.2, # first retry after 200ms
60
60
  multiplier: 1, # subsequent retries wait 1x longer than first retry (no change)
61
61
  tries: 3, # we only need 3 tries (including the first) for the scenario described below
@@ -98,7 +98,7 @@ describe Lhm::SqlRetry do
98
98
  puts "*" * 64
99
99
  # Start a thread to retry, once the lock is held, execute the block
100
100
  @helper.with_waiting_lock do |waiting_connection|
101
- sql_retry = Lhm::SqlRetry.new(waiting_connection, options: {
101
+ sql_retry = Lhm::SqlRetry.new(waiting_connection, retry_options: {
102
102
  base_interval: 0.2, # first retry after 200ms
103
103
  multiplier: 1, # subsequent retries wait 1x longer than first retry (no change)
104
104
  tries: 2, # we need 3 tries (including the first) for the scenario described below, but we only get two...we will fail
@@ -18,7 +18,7 @@ describe Lhm::SqlRetry, "ProxiSQL tests for LHM retry" do
18
18
 
19
19
  @connection = DBConnectionHelper::new_mysql_connection(:proxysql, true, true)
20
20
 
21
- @lhm_retry = Lhm::SqlRetry.new(@connection, options: {},
21
+ @lhm_retry = Lhm::SqlRetry.new(@connection, retry_options: {},
22
22
  reconnect_with_consistent_host: true)
23
23
  end
24
24
 
@@ -38,7 +38,7 @@ describe Lhm::SqlRetry, "ProxiSQL tests for LHM retry" do
38
38
  end
39
39
  end
40
40
  assert_equal Lhm::Error, e.class
41
- assert_match(/LHM tried the reconnection procedure but failed. Latest error:/, e.message)
41
+ assert_match(/LHM tried the reconnection procedure but failed. Aborting/, e.message)
42
42
  end
43
43
 
44
44
  it "Will retry until connection is achieved" do
@@ -61,9 +61,10 @@ describe Lhm::SqlRetry, "ProxiSQL tests for LHM retry" do
61
61
  it "Will abort if new writer is not same host" do
62
62
  # The hostname will be constant before the blip
63
63
  Lhm::SqlRetry.any_instance.stubs(:hostname).returns("mysql-1").then.returns("mysql-2")
64
+ Lhm::SqlRetry.any_instance.stubs(:server_id).returns(1).then.returns(2)
64
65
 
65
66
  # Need new instance for stub to take into effect
66
- lhm_retry = Lhm::SqlRetry.new(@connection, options: {},
67
+ lhm_retry = Lhm::SqlRetry.new(@connection, retry_options: {},
67
68
  reconnect_with_consistent_host: true)
68
69
 
69
70
  e = assert_raises Lhm::Error do
@@ -76,12 +77,12 @@ describe Lhm::SqlRetry, "ProxiSQL tests for LHM retry" do
76
77
  end
77
78
 
78
79
  assert_equal e.class, Lhm::Error
79
- assert_match(/LHM tried the reconnection procedure but failed. Latest error: Reconnected to wrong host/, e.message)
80
+ assert_match(/LHM tried the reconnection procedure but failed. Aborting/, e.message)
80
81
 
81
82
  logs = @logger.string.split("\n")
82
83
 
83
84
  assert logs.first.include?("Lost connection to MySQL, will retry to connect to same host")
84
- assert logs.last.include?("Lost connection to MySQL server at 'reading initial communication packet")
85
+ assert logs.last.include?("Reconnected to wrong host. Started migration on: mysql-1 (server_id: 1), but reconnected to: mysql-2 (server_id: 2).")
85
86
  end
86
87
 
87
88
  it "Will abort if failover happens (mimicked with proxySQL)" do
@@ -98,11 +99,11 @@ describe Lhm::SqlRetry, "ProxiSQL tests for LHM retry" do
98
99
  end
99
100
 
100
101
  assert_equal e.class, Lhm::Error
101
- assert_match(/LHM tried the reconnection procedure but failed. Latest error: Reconnected to wrong host/, e.message)
102
+ assert_match(/LHM tried the reconnection procedure but failed. Aborting/, e.message)
102
103
 
103
104
  logs = @logger.string.split("\n")
104
105
 
105
106
  assert logs.first.include?("Lost connection to MySQL, will retry to connect to same host")
106
- assert logs.last.include?("Lost connection to MySQL server at 'reading initial communication packet")
107
+ assert logs.last.include?("Reconnected to wrong host. Started migration on: mysql-1 (server_id: 1), but reconnected to: mysql-2 (server_id: 2).")
107
108
  end
108
109
  end
data/spec/test_helper.rb CHANGED
@@ -28,6 +28,9 @@ logger = Logger.new STDOUT
28
28
  logger.level = Logger::WARN
29
29
  Lhm.logger = logger
30
30
 
31
+ # Want test to be efficient without having to wait the normal value of 120s
32
+ Lhm::SqlRetry::RECONNECT_RETRY_MAX_ITERATION = 4
33
+
31
34
  def without_verbose(&block)
32
35
  old_verbose, $VERBOSE = $VERBOSE, nil
33
36
  yield