lhm-shopify 3.5.4 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +6 -6
  3. data/Appraisals +8 -13
  4. data/CHANGELOG.md +13 -0
  5. data/Gemfile.lock +22 -20
  6. data/README.md +14 -7
  7. data/dev.yml +12 -8
  8. data/docker-compose.yml +2 -0
  9. data/gemfiles/activerecord_6.0.gemfile +1 -1
  10. data/gemfiles/activerecord_6.0.gemfile.lock +25 -21
  11. data/gemfiles/activerecord_6.1.gemfile.lock +17 -13
  12. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile → activerecord_7.0.gemfile} +1 -1
  13. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile.lock → activerecord_7.0.gemfile.lock} +23 -19
  14. data/gemfiles/{activerecord_5.2.gemfile → activerecord_7.1.0.beta1.gemfile} +1 -3
  15. data/gemfiles/activerecord_7.1.0.beta1.gemfile.lock +81 -0
  16. data/lhm.gemspec +1 -1
  17. data/lib/lhm/sql_helper.rb +1 -1
  18. data/lib/lhm/sql_retry.rb +37 -47
  19. data/lib/lhm/throttler/replica_lag.rb +162 -0
  20. data/lib/lhm/throttler/slave_lag.rb +5 -155
  21. data/lib/lhm/throttler/threads_running.rb +3 -1
  22. data/lib/lhm/throttler.rb +7 -3
  23. data/lib/lhm/version.rb +1 -1
  24. data/spec/.lhm.example +1 -1
  25. data/spec/README.md +8 -9
  26. data/spec/integration/atomic_switcher_spec.rb +2 -2
  27. data/spec/integration/chunk_insert_spec.rb +2 -2
  28. data/spec/integration/chunker_spec.rb +33 -38
  29. data/spec/integration/database.yml +1 -1
  30. data/spec/integration/entangler_spec.rb +4 -4
  31. data/spec/integration/integration_helper.rb +12 -12
  32. data/spec/integration/lhm_spec.rb +41 -32
  33. data/spec/integration/locked_switcher_spec.rb +2 -2
  34. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +6 -5
  35. data/spec/integration/toxiproxy_helper.rb +1 -1
  36. data/spec/test_helper.rb +3 -0
  37. data/spec/unit/printer_spec.rb +2 -6
  38. data/spec/unit/sql_helper_spec.rb +2 -2
  39. data/spec/unit/throttler/{slave_lag_spec.rb → replica_lag_spec.rb} +79 -79
  40. data/spec/unit/throttler/threads_running_spec.rb +18 -0
  41. data/spec/unit/throttler_spec.rb +8 -8
  42. metadata +10 -9
  43. data/gemfiles/activerecord_5.2.gemfile.lock +0 -65
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,9 +31,6 @@ 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
34
  def initialize(connection, retry_options: {}, reconnect_with_consistent_host: false)
32
35
  @connection = connection
33
36
  self.retry_config = retry_options
@@ -38,11 +41,14 @@ module Lhm
38
41
  def with_retries(log_prefix: nil)
39
42
  @log_prefix = log_prefix || "" # No prefix. Just logs
40
43
 
44
+ # Amount of time LHM had to reconnect. Aborting if more than RECONNECTION_MAXIMUM
45
+ reconnection_counter = 0
46
+
41
47
  Retriable.retriable(@retry_config) do
42
48
  # Using begin -> rescue -> end for Ruby 2.4 compatibility
43
49
  begin
44
50
  if @reconnect_with_consistent_host
45
- 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?
46
52
  end
47
53
 
48
54
  yield(@connection)
@@ -51,7 +57,18 @@ module Lhm
51
57
  # The error will be raised the connection is still active (i.e. no need to reconnect) or if the connection is
52
58
  # dead (i.e. not active) and @reconnect_with_host is false (i.e. instructed not to reconnect)
53
59
  raise e if @connection.active? || (!@connection.active? && !@reconnect_with_consistent_host)
54
- 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
55
72
  end
56
73
  end
57
74
  end
@@ -105,34 +122,32 @@ module Lhm
105
122
 
106
123
  def reconnect_with_host_check!
107
124
  log_with_prefix("Lost connection to MySQL, will retry to connect to same host")
108
- begin
109
- Retriable.retriable(host_retry_config) do
125
+
126
+ RECONNECT_RETRY_MAX_ITERATION.times do
127
+ begin
128
+ sleep(RECONNECT_RETRY_INTERVAL)
129
+
110
130
  # tries to reconnect. On failure will trigger a retry
111
131
  @connection.reconnect!
112
132
 
113
133
  if same_host_as_initial?
114
134
  # This is not an actual error, but controlled way to get the parent `Retriable.retriable` to retry
115
135
  # the statement that failed (since the Retriable gem only retries on errors).
116
- 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
117
138
  else
118
139
  # New Master --> abort LHM (reconnecting will not change anything)
119
- 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
120
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
121
148
  end
122
- rescue StandardError => e
123
- # The parent Retriable.retriable is configured to retry if it encounters an error with the success message.
124
- # Therefore, if the connection is re-established successfully AND the host is the same, LHM can retry the query
125
- # that originally failed.
126
- raise e if reconnect_successful?(e)
127
- # If the connection was not successful, the parent retriable will raise any error that originated from the
128
- # `@connection.reconnect!`
129
- # Therefore, this error will cause the LHM to abort
130
- raise Lhm::Error.new("LHM tried the reconnection procedure but failed. Latest error: #{e.message}")
131
149
  end
132
- end
133
-
134
- def reconnect_successful?(e)
135
- e.is_a?(ReconnectToHostSuccessful)
150
+ false
136
151
  end
137
152
 
138
153
  # For a full list of configuration options see https://github.com/kamui/retriable
@@ -149,9 +164,6 @@ module Lhm
149
164
  /Unknown MySQL server host/,
150
165
  /connection is locked to hostgroup/,
151
166
  /The MySQL server is running with the --read-only option so it cannot execute this statement/,
152
- ],
153
- ReconnectToHostSuccessful => [
154
- /#{RECONNECT_SUCCESSFUL_MESSAGE}/
155
167
  ]
156
168
  },
157
169
  multiplier: 1, # each successive interval grows by this factor
@@ -159,28 +171,6 @@ module Lhm
159
171
  tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
160
172
  rand_factor: 0, # percentage to randomize the next retry interval time
161
173
  max_elapsed_time: Float::INFINITY, # max total time in seconds that code is allowed to keep being retried
162
- on_retry: Proc.new do |exception, try_number, total_elapsed_time, next_interval|
163
- if reconnect_successful?(exception)
164
- log_with_prefix("#{exception.message} -- triggering retry", :info)
165
- else
166
- log_with_prefix("#{exception.class}: '#{exception.message}' - #{try_number} tries in #{total_elapsed_time} seconds and #{next_interval} seconds until the next try.", :error)
167
- end
168
- end
169
- }.freeze
170
- end
171
-
172
- def host_retry_config
173
- {
174
- on: {
175
- StandardError => [
176
- /Lost connection to MySQL server at 'reading initial communication packet'/
177
- ]
178
- },
179
- multiplier: 1, # each successive interval grows by this factor
180
- base_interval: 0.25, # the initial interval in seconds between tries.
181
- tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
182
- rand_factor: 0, # percentage to randomize the next retry interval time
183
- max_elapsed_time: Float::INFINITY, # max total time in seconds that code is allowed to keep being retried
184
174
  on_retry: Proc.new do |exception, try_number, total_elapsed_time, next_interval|
185
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)
186
176
  end
@@ -0,0 +1,162 @@
1
+ module Lhm
2
+ module Throttler
3
+
4
+ def self.format_hosts(hosts)
5
+ formatted_hosts = []
6
+ hosts.each do |host|
7
+ if host && !host.match(/localhost/) && !host.match(/127.0.0.1/)
8
+ formatted_hosts << host.partition(':')[0]
9
+ end
10
+ end
11
+ formatted_hosts
12
+ end
13
+
14
+ class ReplicaLag
15
+ include Command
16
+
17
+ INITIAL_TIMEOUT = 0.1
18
+ DEFAULT_STRIDE = 2_000
19
+ DEFAULT_MAX_ALLOWED_LAG = 10
20
+
21
+ MAX_TIMEOUT = INITIAL_TIMEOUT * 1024
22
+
23
+ attr_accessor :timeout_seconds, :allowed_lag, :stride, :connection
24
+
25
+ def initialize(options = {})
26
+ @timeout_seconds = INITIAL_TIMEOUT
27
+ @stride = options[:stride] || DEFAULT_STRIDE
28
+ @allowed_lag = options[:allowed_lag] || DEFAULT_MAX_ALLOWED_LAG
29
+ @replicas = {}
30
+ @get_config = options[:current_config]
31
+ @check_only = options[:check_only]
32
+ end
33
+
34
+ def execute
35
+ sleep(throttle_seconds)
36
+ end
37
+
38
+ private
39
+
40
+ def throttle_seconds
41
+ lag = max_current_replica_lag
42
+
43
+ if lag > @allowed_lag && @timeout_seconds < MAX_TIMEOUT
44
+ Lhm.logger.info("Increasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds * 2} because #{lag} seconds of replica lag detected is greater than the maximum of #{@allowed_lag} seconds allowed.")
45
+ @timeout_seconds = @timeout_seconds * 2
46
+ elsif lag <= @allowed_lag && @timeout_seconds > INITIAL_TIMEOUT
47
+ Lhm.logger.info("Decreasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds / 2} because #{lag} seconds of replica lag detected is less than or equal to the #{@allowed_lag} seconds allowed.")
48
+ @timeout_seconds = @timeout_seconds / 2
49
+ else
50
+ @timeout_seconds
51
+ end
52
+ end
53
+
54
+ def replicas
55
+ @replicas[@connection] ||= get_replicas
56
+ end
57
+
58
+ def get_replicas
59
+ replicas = []
60
+ if @check_only.nil? or !@check_only.respond_to?(:call)
61
+ replica_hosts = master_replica_hosts
62
+ while replica_hosts.any? do
63
+ host = replica_hosts.pop
64
+ replica = Replica.new(host, @get_config)
65
+ if !replicas.map(&:host).include?(host) && replica.connection
66
+ replicas << replica
67
+ replica_hosts.concat(replica.replica_hosts)
68
+ end
69
+ end
70
+ else
71
+ replica_config = @check_only.call
72
+ replicas << Replica.new(replica_config['host'], @get_config)
73
+ end
74
+ replicas
75
+ end
76
+
77
+ def master_replica_hosts
78
+ Throttler.format_hosts(@connection.select_values(Replica::SQL_SELECT_REPLICA_HOSTS))
79
+ end
80
+
81
+ def max_current_replica_lag
82
+ max = replicas.map { |replica| replica.lag }.push(0).max
83
+ Lhm.logger.info "Max current replica lag: #{max}"
84
+ max
85
+ end
86
+ end
87
+
88
+ class Replica
89
+ SQL_SELECT_REPLICA_HOSTS = "SELECT host FROM information_schema.processlist WHERE command LIKE 'Binlog Dump%'"
90
+ SQL_SELECT_MAX_REPLICA_LAG = 'SHOW SLAVE STATUS'
91
+
92
+ attr_reader :host, :connection
93
+
94
+ def initialize(host, connection_config = nil)
95
+ @host = host
96
+ @connection_config = prepare_connection_config(connection_config)
97
+ @connection = client(@connection_config)
98
+ end
99
+
100
+ def replica_hosts
101
+ Throttler.format_hosts(query_connection(SQL_SELECT_REPLICA_HOSTS, 'host'))
102
+ end
103
+
104
+ def lag
105
+ query_connection(SQL_SELECT_MAX_REPLICA_LAG, 'Seconds_Behind_Master').first.to_i
106
+ end
107
+
108
+ private
109
+
110
+ def client(config)
111
+ begin
112
+ Lhm.logger.info "Connecting to #{@host} on database: #{config[:database]}"
113
+ Mysql2::Client.new(config)
114
+ rescue Mysql2::Error => e
115
+ Lhm.logger.info "Error connecting to #{@host}: #{e}"
116
+ nil
117
+ end
118
+ end
119
+
120
+ def prepare_connection_config(config_proc)
121
+ config = if config_proc
122
+ if config_proc.respond_to?(:call) # if we get a proc
123
+ config_proc.call
124
+ else
125
+ raise ArgumentError, "Expected #{config_proc.inspect} to respond to `call`"
126
+ end
127
+ else
128
+ db_config
129
+ end
130
+ config.deep_symbolize_keys!
131
+ config[:host] = @host
132
+ config
133
+ end
134
+
135
+ def query_connection(query, result)
136
+ begin
137
+ @connection.query(query).map { |row| row[result] }
138
+ rescue Mysql2::Error => e
139
+ Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
140
+ [nil]
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def db_config
147
+ if ar_supports_db_config?
148
+ ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
149
+ else
150
+ ActiveRecord::Base.connection_pool.spec.config.dup
151
+ end
152
+ end
153
+
154
+ def ar_supports_db_config?
155
+ # https://api.rubyonrails.org/v6.0/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has spec
156
+ # vs
157
+ # https://api.rubyonrails.org/v6.1/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has db_config
158
+ ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
159
+ end
160
+ end
161
+ end
162
+ end
@@ -1,161 +1,11 @@
1
+ require 'lhm/throttler/replica_lag'
2
+
1
3
  module Lhm
2
4
  module Throttler
3
-
4
- def self.format_hosts(hosts)
5
- formatted_hosts = []
6
- hosts.each do |host|
7
- if host && !host.match(/localhost/) && !host.match(/127.0.0.1/)
8
- formatted_hosts << host.partition(':')[0]
9
- end
10
- end
11
- formatted_hosts
12
- end
13
-
14
- class SlaveLag
15
- include Command
16
-
17
- INITIAL_TIMEOUT = 0.1
18
- DEFAULT_STRIDE = 2_000
19
- DEFAULT_MAX_ALLOWED_LAG = 10
20
-
21
- MAX_TIMEOUT = INITIAL_TIMEOUT * 1024
22
-
23
- attr_accessor :timeout_seconds, :allowed_lag, :stride, :connection
24
-
5
+ class SlaveLag < ReplicaLag
25
6
  def initialize(options = {})
26
- @timeout_seconds = INITIAL_TIMEOUT
27
- @stride = options[:stride] || DEFAULT_STRIDE
28
- @allowed_lag = options[:allowed_lag] || DEFAULT_MAX_ALLOWED_LAG
29
- @slaves = {}
30
- @get_config = options[:current_config]
31
- @check_only = options[:check_only]
32
- end
33
-
34
- def execute
35
- sleep(throttle_seconds)
36
- end
37
-
38
- private
39
-
40
- def throttle_seconds
41
- lag = max_current_slave_lag
42
-
43
- if lag > @allowed_lag && @timeout_seconds < MAX_TIMEOUT
44
- Lhm.logger.info("Increasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds * 2} because #{lag} seconds of slave lag detected is greater than the maximum of #{@allowed_lag} seconds allowed.")
45
- @timeout_seconds = @timeout_seconds * 2
46
- elsif lag <= @allowed_lag && @timeout_seconds > INITIAL_TIMEOUT
47
- Lhm.logger.info("Decreasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds / 2} because #{lag} seconds of slave lag detected is less than or equal to the #{@allowed_lag} seconds allowed.")
48
- @timeout_seconds = @timeout_seconds / 2
49
- else
50
- @timeout_seconds
51
- end
52
- end
53
-
54
- def slaves
55
- @slaves[@connection] ||= get_slaves
56
- end
57
-
58
- def get_slaves
59
- slaves = []
60
- if @check_only.nil? or !@check_only.respond_to?(:call)
61
- slave_hosts = master_slave_hosts
62
- while slave_hosts.any? do
63
- host = slave_hosts.pop
64
- slave = Slave.new(host, @get_config)
65
- if !slaves.map(&:host).include?(host) && slave.connection
66
- slaves << slave
67
- slave_hosts.concat(slave.slave_hosts)
68
- end
69
- end
70
- else
71
- slave_config = @check_only.call
72
- slaves << Slave.new(slave_config['host'], @get_config)
73
- end
74
- slaves
75
- end
76
-
77
- def master_slave_hosts
78
- Throttler.format_hosts(@connection.select_values(Slave::SQL_SELECT_SLAVE_HOSTS))
79
- end
80
-
81
- def max_current_slave_lag
82
- max = slaves.map { |slave| slave.lag }.push(0).max
83
- Lhm.logger.info "Max current slave lag: #{max}"
84
- max
85
- end
86
- end
87
-
88
- class Slave
89
- SQL_SELECT_SLAVE_HOSTS = "SELECT host FROM information_schema.processlist WHERE command LIKE 'Binlog Dump%'"
90
- SQL_SELECT_MAX_SLAVE_LAG = 'SHOW SLAVE STATUS'
91
-
92
- attr_reader :host, :connection
93
-
94
- def initialize(host, connection_config = nil)
95
- @host = host
96
- @connection_config = prepare_connection_config(connection_config)
97
- @connection = client(@connection_config)
98
- end
99
-
100
- def slave_hosts
101
- Throttler.format_hosts(query_connection(SQL_SELECT_SLAVE_HOSTS, 'host'))
102
- end
103
-
104
- def lag
105
- query_connection(SQL_SELECT_MAX_SLAVE_LAG, 'Seconds_Behind_Master').first.to_i
106
- end
107
-
108
- private
109
-
110
- def client(config)
111
- begin
112
- Lhm.logger.info "Connecting to #{@host} on database: #{config[:database]}"
113
- Mysql2::Client.new(config)
114
- rescue Mysql2::Error => e
115
- Lhm.logger.info "Error connecting to #{@host}: #{e}"
116
- nil
117
- end
118
- end
119
-
120
- def prepare_connection_config(config_proc)
121
- config = if config_proc
122
- if config_proc.respond_to?(:call) # if we get a proc
123
- config_proc.call
124
- else
125
- raise ArgumentError, "Expected #{config_proc.inspect} to respond to `call`"
126
- end
127
- else
128
- db_config
129
- end
130
- config.deep_symbolize_keys!
131
- config[:host] = @host
132
- config
133
- end
134
-
135
- def query_connection(query, result)
136
- begin
137
- @connection.query(query).map { |row| row[result] }
138
- rescue Mysql2::Error => e
139
- Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
140
- [nil]
141
- end
142
- end
143
-
144
- private
145
-
146
- def db_config
147
- if ar_supports_db_config?
148
- ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
149
- else
150
- ActiveRecord::Base.connection_pool.spec.config.dup
151
- end
152
- end
153
-
154
- def ar_supports_db_config?
155
- # https://api.rubyonrails.org/v6.0/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has spec
156
- # vs
157
- # https://api.rubyonrails.org/v6.1/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has db_config
158
- ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
7
+ Lhm.logger.warn("Class `SlaveLag` is deprecated. Use `ReplicaLag` class instead.")
8
+ super(options)
159
9
  end
160
10
  end
161
11
  end
@@ -3,14 +3,16 @@ module Lhm
3
3
  class ThreadsRunning
4
4
  include Command
5
5
 
6
+ DEFAULT_STRIDE = 2_000
6
7
  DEFAULT_INITIAL_TIMEOUT = 0.1
7
8
  DEFAULT_HEALTHY_RANGE = (0..50)
8
9
 
9
- attr_accessor :timeout_seconds, :healthy_range, :connection
10
+ attr_accessor :timeout_seconds, :healthy_range, :connection, :stride
10
11
  attr_reader :max_timeout_seconds, :initial_timeout_seconds
11
12
 
12
13
  def initialize(options = {})
13
14
  @initial_timeout_seconds = options[:initial_timeout] || DEFAULT_INITIAL_TIMEOUT
15
+ @stride = options[:stride] || DEFAULT_STRIDE
14
16
  @max_timeout_seconds = options[:max_timeout] || (@initial_timeout_seconds * 1024)
15
17
  @timeout_seconds = @initial_timeout_seconds
16
18
  @healthy_range = options[:healthy_range] || DEFAULT_HEALTHY_RANGE
data/lib/lhm/throttler.rb CHANGED
@@ -1,12 +1,16 @@
1
1
  require 'lhm/throttler/time'
2
+ require 'lhm/throttler/replica_lag'
2
3
  require 'lhm/throttler/slave_lag'
3
4
  require 'lhm/throttler/threads_running'
4
5
 
5
6
  module Lhm
6
7
  module Throttler
7
- CLASSES = { :time_throttler => Throttler::Time,
8
- :slave_lag_throttler => Throttler::SlaveLag,
9
- :threads_running_throttler => Throttler::ThreadsRunning }
8
+ CLASSES = {
9
+ :time_throttler => Throttler::Time,
10
+ :replica_lag_throttler => Throttler::ReplicaLag,
11
+ :slave_lag_throttler => Throttler::SlaveLag,
12
+ :threads_running_throttler => Throttler::ThreadsRunning
13
+ }
10
14
 
11
15
  def throttler
12
16
  @throttler ||= Throttler::Time.new
data/lib/lhm/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Schmidt
3
3
 
4
4
  module Lhm
5
- VERSION = '3.5.4'
5
+ VERSION = '4.0.0'
6
6
  end
data/spec/.lhm.example CHANGED
@@ -1,4 +1,4 @@
1
1
  mysqldir=/usr/local/mysql
2
2
  basedir=~/lhm-cluster
3
3
  master_port=3306
4
- slave_port=3307
4
+ replica_port=3307
data/spec/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Preparing for master slave integration tests
1
+ # Preparing for master replica integration tests
2
2
 
3
3
  ## Configuration
4
4
 
@@ -7,10 +7,10 @@ create ~/.lhm:
7
7
  mysqldir=/usr/local/mysql
8
8
  basedir=~/lhm-cluster
9
9
  master_port=3306
10
- slave_port=3307
10
+ replica_port=3307
11
11
 
12
12
  mysqldir specifies the location of your mysql install. basedir is the
13
- directory master and slave databases will get installed into.
13
+ directory master and replica databases will get installed into.
14
14
 
15
15
  ## Automatic setup
16
16
 
@@ -18,8 +18,8 @@ directory master and slave databases will get installed into.
18
18
 
19
19
  bin/lhm-spec-clobber.sh
20
20
 
21
- You can set the integration specs up to run against a master slave setup by
22
- running the included that. This deletes the configured lhm master slave setup and reinstalls and configures a master slave setup.
21
+ You can set the integration specs up to run against a master replica setup by
22
+ running the included that. This deletes the configured lhm master replica setup and reinstalls and configures a master replica setup.
23
23
 
24
24
  Follow the manual instructions if you want more control over this process.
25
25
 
@@ -33,7 +33,7 @@ Follow the manual instructions if you want more control over this process.
33
33
 
34
34
  basedir=/opt/lhm-luster
35
35
  mysqld --defaults-file="$basedir/master/my.cnf"
36
- mysqld --defaults-file="$basedir/slave/my.cnf"
36
+ mysqld --defaults-file="$basedir/replica/my.cnf"
37
37
 
38
38
  ### run the grants
39
39
 
@@ -46,13 +46,12 @@ Setup the dependency gems
46
46
  export BUNDLE_GEMFILE=gemfiles/ar-4.2_mysql2.gemfile
47
47
  bundle install
48
48
 
49
- To run specs in slave mode, set the MASTER_SLAVE=1 when running tests:
49
+ To run specs in replica mode, set the MASTER_REPLICA=1 when running tests:
50
50
 
51
- MASTER_SLAVE=1 bundle exec rake specs
51
+ MASTER_REPLICA=1 bundle exec rake specs
52
52
 
53
53
  # connecting
54
54
 
55
55
  you can connect by running (with the respective ports):
56
56
 
57
57
  mysql --protocol=TCP -p3307
58
-
@@ -110,7 +110,7 @@ describe Lhm::AtomicSwitcher do
110
110
  switcher = Lhm::AtomicSwitcher.new(@migration, connection)
111
111
  switcher.run
112
112
 
113
- slave do
113
+ replica do
114
114
  value(data_source_exists?(@origin)).must_equal true
115
115
  value(table_read(@migration.archive_name).columns.keys).must_include 'origin'
116
116
  end
@@ -120,7 +120,7 @@ describe Lhm::AtomicSwitcher do
120
120
  switcher = Lhm::AtomicSwitcher.new(@migration, connection)
121
121
  switcher.run
122
122
 
123
- slave do
123
+ replica do
124
124
  value(data_source_exists?(@destination)).must_equal false
125
125
  value(table_read(@origin.name).columns.keys).must_include 'destination'
126
126
  end
@@ -19,10 +19,10 @@ describe Lhm::ChunkInsert do
19
19
  assert_equal 1, @instance.insert_and_return_count_of_rows_created
20
20
  end
21
21
 
22
- it "inserts the record into the slave" do
22
+ it "inserts the record into the replica" do
23
23
  @instance.insert_and_return_count_of_rows_created
24
24
 
25
- slave do
25
+ replica do
26
26
  value(count_all(@destination.name)).must_equal(1)
27
27
  end
28
28
  end