lhm-teak 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +43 -0
  3. data/.gitignore +12 -0
  4. data/.rubocop.yml +183 -0
  5. data/.travis.yml +21 -0
  6. data/Appraisals +24 -0
  7. data/CHANGELOG.md +254 -0
  8. data/Gemfile +5 -0
  9. data/Gemfile.lock +67 -0
  10. data/LICENSE +27 -0
  11. data/README.md +335 -0
  12. data/Rakefile +33 -0
  13. data/dev.yml +45 -0
  14. data/docker-compose.yml +60 -0
  15. data/gemfiles/activerecord_5.2.gemfile +9 -0
  16. data/gemfiles/activerecord_5.2.gemfile.lock +66 -0
  17. data/gemfiles/activerecord_6.0.gemfile +7 -0
  18. data/gemfiles/activerecord_6.0.gemfile.lock +68 -0
  19. data/gemfiles/activerecord_6.1.gemfile +7 -0
  20. data/gemfiles/activerecord_6.1.gemfile.lock +67 -0
  21. data/gemfiles/activerecord_7.0.0.alpha2.gemfile +7 -0
  22. data/gemfiles/activerecord_7.0.0.alpha2.gemfile.lock +65 -0
  23. data/lhm.gemspec +38 -0
  24. data/lib/lhm/atomic_switcher.rb +46 -0
  25. data/lib/lhm/chunk_finder.rb +62 -0
  26. data/lib/lhm/chunk_insert.rb +61 -0
  27. data/lib/lhm/chunker.rb +95 -0
  28. data/lib/lhm/cleanup/current.rb +71 -0
  29. data/lib/lhm/command.rb +48 -0
  30. data/lib/lhm/connection.rb +108 -0
  31. data/lib/lhm/entangler.rb +112 -0
  32. data/lib/lhm/intersection.rb +51 -0
  33. data/lib/lhm/invoker.rb +100 -0
  34. data/lib/lhm/locked_switcher.rb +76 -0
  35. data/lib/lhm/migration.rb +51 -0
  36. data/lib/lhm/migrator.rb +244 -0
  37. data/lib/lhm/printer.rb +63 -0
  38. data/lib/lhm/proxysql_helper.rb +10 -0
  39. data/lib/lhm/railtie.rb +9 -0
  40. data/lib/lhm/sql_helper.rb +77 -0
  41. data/lib/lhm/sql_retry.rb +180 -0
  42. data/lib/lhm/table.rb +121 -0
  43. data/lib/lhm/table_name.rb +23 -0
  44. data/lib/lhm/test_support.rb +35 -0
  45. data/lib/lhm/throttler/slave_lag.rb +162 -0
  46. data/lib/lhm/throttler/threads_running.rb +53 -0
  47. data/lib/lhm/throttler/time.rb +29 -0
  48. data/lib/lhm/throttler.rb +36 -0
  49. data/lib/lhm/timestamp.rb +11 -0
  50. data/lib/lhm/version.rb +6 -0
  51. data/lib/lhm-shopify.rb +1 -0
  52. data/lib/lhm.rb +156 -0
  53. data/scripts/helpers/wait-for-dbs.sh +21 -0
  54. data/scripts/mysql/reader/create_replication.sql +10 -0
  55. data/scripts/mysql/writer/create_test_db.sql +1 -0
  56. data/scripts/mysql/writer/create_users.sql +6 -0
  57. data/scripts/proxysql/proxysql.cnf +117 -0
  58. data/shipit.rubygems.yml +0 -0
  59. data/spec/.lhm.example +4 -0
  60. data/spec/README.md +58 -0
  61. data/spec/fixtures/bigint_table.ddl +4 -0
  62. data/spec/fixtures/composite_primary_key.ddl +6 -0
  63. data/spec/fixtures/composite_primary_key_dest.ddl +6 -0
  64. data/spec/fixtures/custom_primary_key.ddl +6 -0
  65. data/spec/fixtures/custom_primary_key_dest.ddl +6 -0
  66. data/spec/fixtures/destination.ddl +6 -0
  67. data/spec/fixtures/lines.ddl +7 -0
  68. data/spec/fixtures/origin.ddl +6 -0
  69. data/spec/fixtures/permissions.ddl +5 -0
  70. data/spec/fixtures/small_table.ddl +4 -0
  71. data/spec/fixtures/tracks.ddl +5 -0
  72. data/spec/fixtures/users.ddl +14 -0
  73. data/spec/fixtures/wo_id_int_column.ddl +6 -0
  74. data/spec/integration/atomic_switcher_spec.rb +129 -0
  75. data/spec/integration/chunk_insert_spec.rb +30 -0
  76. data/spec/integration/chunker_spec.rb +269 -0
  77. data/spec/integration/cleanup_spec.rb +147 -0
  78. data/spec/integration/database.yml +25 -0
  79. data/spec/integration/entangler_spec.rb +68 -0
  80. data/spec/integration/integration_helper.rb +252 -0
  81. data/spec/integration/invoker_spec.rb +33 -0
  82. data/spec/integration/lhm_spec.rb +659 -0
  83. data/spec/integration/lock_wait_timeout_spec.rb +30 -0
  84. data/spec/integration/locked_switcher_spec.rb +50 -0
  85. data/spec/integration/proxysql_spec.rb +34 -0
  86. data/spec/integration/sql_retry/db_connection_helper.rb +52 -0
  87. data/spec/integration/sql_retry/lock_wait_spec.rb +127 -0
  88. data/spec/integration/sql_retry/lock_wait_timeout_test_helper.rb +114 -0
  89. data/spec/integration/sql_retry/proxysql_helper.rb +22 -0
  90. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +109 -0
  91. data/spec/integration/table_spec.rb +83 -0
  92. data/spec/integration/toxiproxy_helper.rb +40 -0
  93. data/spec/test_helper.rb +69 -0
  94. data/spec/unit/atomic_switcher_spec.rb +29 -0
  95. data/spec/unit/chunk_finder_spec.rb +73 -0
  96. data/spec/unit/chunk_insert_spec.rb +67 -0
  97. data/spec/unit/chunker_spec.rb +176 -0
  98. data/spec/unit/connection_spec.rb +111 -0
  99. data/spec/unit/entangler_spec.rb +187 -0
  100. data/spec/unit/intersection_spec.rb +51 -0
  101. data/spec/unit/lhm_spec.rb +46 -0
  102. data/spec/unit/locked_switcher_spec.rb +46 -0
  103. data/spec/unit/migrator_spec.rb +144 -0
  104. data/spec/unit/printer_spec.rb +85 -0
  105. data/spec/unit/sql_helper_spec.rb +28 -0
  106. data/spec/unit/table_name_spec.rb +39 -0
  107. data/spec/unit/table_spec.rb +47 -0
  108. data/spec/unit/throttler/slave_lag_spec.rb +322 -0
  109. data/spec/unit/throttler/threads_running_spec.rb +64 -0
  110. data/spec/unit/throttler_spec.rb +124 -0
  111. data/spec/unit/unit_helper.rb +26 -0
  112. metadata +366 -0
data/README.md ADDED
@@ -0,0 +1,335 @@
1
+ # Large Hadron Migrator
2
+
3
+ [![Tests](https://github.com/Shopify/lhm/actions/workflows/test.yml/badge.svg)](https://github.com/Shopify/lhm/actions/workflows/test.yml)
4
+
5
+ This is the Shopify fork of [SoundCloud's LHM](https://github.com/soundcloud/lhm). The
6
+ following description, originally from SoundCloud (with minor updates by Shopify),
7
+ gives some of the flavor around its original creation, and its choice of name...
8
+
9
+ Rails-style database migrations are a useful way to evolve your database schema in
10
+ an agile manner. Most Rails projects start like this, and at first, making
11
+ changes is fast and easy.
12
+
13
+ That is, until your tables grow to millions or billions of records. At this point,
14
+ the locking nature of `ALTER TABLE` may take your site down for hours or more
15
+ while critical tables are migrated. In order to avoid this, developers begin
16
+ to design around the problem by introducing join tables or moving the data
17
+ into another layer. Development gets less and less agile as tables grow and
18
+ grow. To make the problem worse, adding or changing indices to optimize data
19
+ access becomes just as difficult.
20
+
21
+ *Side effects may include black holes and universe implosion.*
22
+
23
+ There are few things that can be done at the server or engine level. It is
24
+ possible to change default values in an `ALTER TABLE` without locking the
25
+ table. InnoDB provides facilities for online index creation, but that only
26
+ solves half the problem.
27
+
28
+ At SoundCloud we started having migration pains quite a while ago, and after
29
+ looking around for third party solutions, we decided to create our
30
+ own. We called it **Large Hadron Migrator**, and it is a Ruby Gem that provides
31
+ facilities for online ActiveRecord migrations.
32
+
33
+ ![The Large Hadron Collider at CERN](http://farm4.static.flickr.com/3093/2844971993_17f2ddf2a8_z.jpg)
34
+
35
+ The [Large Hadron Collider](http://en.wikipedia.org/wiki/Large_Hadron_Collider) at [CERN](https://en.wikipedia.org/wiki/CERN) near Geneva, Switzerland.
36
+
37
+ ## The idea
38
+
39
+ The basic idea is to perform the migration online while the system is live,
40
+ without locking the table. In contrast to [OAK][0] and the [facebook tool][1], we
41
+ only use a copy table and triggers.
42
+
43
+ LHM is a test-driven Ruby solution which can easily be dropped into an ActiveRecord
44
+ migration. It presumes a single auto-incremented numeric primary key called `id` as
45
+ per the Rails convention. Unlike [Matt Freels's `table_migrator` solution][2],
46
+ it does not require the presence of an indexed `updated_at` column.
47
+
48
+ ## Requirements
49
+
50
+ LHM currently only works with MySQL databases and requires an established
51
+ ActiveRecord connection.
52
+
53
+ ## Limitations
54
+
55
+ Due to the Chunker implementation, LHM requires that the table to migrate has a
56
+ a single integer numeric key column named `id`.
57
+
58
+ ## Installation
59
+
60
+ Install it via `gem install lhm-shopify` or by adding `gem "lhm-shopify"` to your `Gemfile`.
61
+
62
+ ## Usage
63
+
64
+ You can invoke LHM directly from a plain Ruby file after connecting ActiveRecord
65
+ to your MySQL instance:
66
+
67
+ ```ruby
68
+ require 'lhm'
69
+
70
+ ActiveRecord::Base.establish_connection(
71
+ :adapter => 'mysql',
72
+ :host => '127.0.0.1',
73
+ :database => 'lhm'
74
+ )
75
+
76
+ # and migrate
77
+ Lhm.change_table :users do |m|
78
+ m.add_column :arbitrary, "INT(12)"
79
+ m.add_index [:arbitrary_id, :created_at]
80
+ m.ddl("alter table %s add column flag tinyint(1)" % m.name)
81
+ end
82
+ ```
83
+
84
+ To use LHM from an `ActiveRecord::Migration` in a Rails project, add it to your
85
+ `Gemfile`, then invoke as follows:
86
+
87
+ ```ruby
88
+ require 'lhm'
89
+
90
+ class MigrateUsers < ActiveRecord::Migration
91
+ def self.up
92
+ Lhm.change_table :users do |m|
93
+ m.add_column :arbitrary, "INT(12)"
94
+ m.add_index [:arbitrary_id, :created_at]
95
+ m.ddl("alter table %s add column flag tinyint(1)" % m.name)
96
+ end
97
+ end
98
+
99
+ def self.down
100
+ Lhm.change_table :users do |m|
101
+ m.remove_index [:arbitrary_id, :created_at]
102
+ m.remove_column :arbitrary
103
+ end
104
+ end
105
+ end
106
+ ```
107
+
108
+ **Note:** LHM does not delete the old, leftover table. This is intentional, in order
109
+ to prevent accidental data loss. After successful or failed LHM migrations, these leftover
110
+ tables must be cleaned up.
111
+
112
+ ### Usage with ProxySQL
113
+ LHM can recover from connection loss. However, when used in conjunction with ProxySQL, there are multiple ways that
114
+ connection loss could induce data loss (if triggered by a failover). Therefore it will perform additional checks to
115
+ ensure that the MySQL host stays consistent across the schema migrations if the feature is enabled.
116
+ This is done by tagging every query with `/*maintenance:lhm*/`, which will be recognized by ProxySQL.
117
+ However, to get this feature working, a new ProxySQL query rule must be added.
118
+ ```cnf
119
+ {
120
+ rule_id = <rule id>
121
+ active = 1
122
+ match_pattern = "maintenance:lhm"
123
+ destination_hostgroup = <MySQL writer's hostgroup>
124
+ }
125
+ ```
126
+
127
+ This will ensure that all relevant queries are forwarded to the current writer.
128
+
129
+ Also, ProxySQL disables [multiplexing](https://proxysql.com/documentation/multiplexing/) for `select` on `@@` variables.
130
+ Therefore, the following rules must be added to ensure that queries (even if tagged with `/*maintenance:lhm*/`) get
131
+ forwarded to the right target.
132
+ ```cnf
133
+ {
134
+ rule_id = <rule id>
135
+ active = 1
136
+ match_digest = "@@global\.server_id"
137
+ multiplex = 2
138
+ },
139
+ {
140
+ rule_id = <rule id>
141
+ active = 1
142
+ match_digest = "@@global\.hostname"
143
+ multiplex = 2
144
+ }
145
+ ```
146
+
147
+ Once these changes are added to the ProxySQL configuration (either through `.cnf` or dynamically through the admin interface),
148
+ the feature can be enabled. This is done by adding this flag when providing options to the migration:
149
+ ```ruby
150
+ Lhm.change_table(..., options: {reconnect_with_consistent_host: true}) do |t|
151
+ ...
152
+ end
153
+ ```
154
+ **Note**: This feature is disabled by default
155
+
156
+ ## Throttler
157
+
158
+ LHM uses a throttling mechanism to read data in your original table. By default, 2,000 rows are read each 0.1 second. If you want to change that behaviour, you can pass an instance of a throttler with the `throttler` option. In this example, 1,000 rows will be read with a 10 second delay between each processing:
159
+
160
+ ```ruby
161
+ my_throttler = Lhm::Throttler::Time.new(stride: 1000, delay: 10)
162
+
163
+ Lhm.change_table :users, throttler: my_throttler do |m|
164
+ ...
165
+ end
166
+ ```
167
+
168
+ ### SlaveLag Throttler
169
+
170
+ Lhm uses by default the time throttler, however a better solution is to throttle the copy of the data
171
+ depending on the time that the slaves are behind. To use the SlaveLag throttler:
172
+
173
+ ```ruby
174
+ Lhm.change_table :users, throttler: :slave_lag_throttler do |m|
175
+ ...
176
+ end
177
+ ```
178
+
179
+ Or to set that as default throttler, use the following (for instance in a Rails initializer):
180
+
181
+ ```ruby
182
+ Lhm.setup_throttler(:slave_lag_throttler)
183
+ ```
184
+
185
+ ### ThreadsRunning Throttler
186
+
187
+ If you don't have access to connect directly to your replicas, you can also
188
+ throttle based on the number of threads running in MySQL, as a proxy for "is
189
+ this operation causing excessive load":
190
+
191
+ ```ruby
192
+ Lhm.change_table :users, throttler: :threads_running_throttler do |m|
193
+ ...
194
+ end
195
+ ```
196
+
197
+ Or to set that as default throttler, use the following (for instance in a Rails initializer):
198
+
199
+ ```ruby
200
+ Lhm.setup_throttler(:threads_running_throttler)
201
+ ```
202
+
203
+ ## Table rename strategies
204
+
205
+ There are two different table rename strategies available: `LockedSwitcher` and
206
+ `AtomicSwitcher`.
207
+
208
+ The `LockedSwitcher` strategy locks the table being migrated and issues two `ALTER TABLE` statements. The `AtomicSwitcher` uses a single atomic `RENAME TABLE` query and is the favored solution.
209
+
210
+ LHM chooses `AtomicSwitcher` if no strategy is specified, **unless** your version of MySQL is
211
+ affected by [binlog bug #39675](http://bugs.mysql.com/bug.php?id=39675). If your version is
212
+ affected, LHM will raise an error if you don't specify a strategy. You're recommended
213
+ to use the `LockedSwitcher` in these cases to avoid replication issues.
214
+
215
+ To specify the strategy in your migration:
216
+
217
+ ```ruby
218
+ Lhm.change_table :users, :atomic_switch => true do |m|
219
+ ...
220
+ end
221
+ ```
222
+
223
+ ## Limiting the data that is migrated
224
+
225
+ For instances where you want to limit the data that is migrated to the new
226
+ table by some conditions, you may tell the migration to filter by a set of
227
+ conditions:
228
+
229
+ ```ruby
230
+ Lhm.change_table(:sounds) do |m|
231
+ m.filter("inner join users on users.`id` = sounds.`user_id` and sounds.`public` = 1")
232
+ end
233
+ ```
234
+
235
+ Note that this SQL will be inserted into the copy directly after the `FROM` clause
236
+ so be sure to use `INNER JOIN` or `OUTER JOIN` syntax and not comma-joins. These
237
+ conditions will not affect the triggers, so any modifications to the table
238
+ during the run will happen on the new table as well.
239
+
240
+ ## Cleaning up after an interrupted Lhm run
241
+
242
+ If an LHM migration is interrupted, it may leave behind the temporary tables
243
+ and/or triggers used in the migration. If the migration is re-started, the
244
+ unexpected presence of these tables will cause an error.
245
+
246
+ In this case, `Lhm.cleanup` can be used to drop any orphaned LHM temporary tables or triggers.
247
+
248
+ To see what LHM tables/triggers are found:
249
+
250
+ ```ruby
251
+ Lhm.cleanup
252
+ ```
253
+
254
+ To remove any LHM tables/triggers found:
255
+
256
+ ```ruby
257
+ Lhm.cleanup(true)
258
+ ```
259
+
260
+ Optionally, only remove tables up to a specific time, if you want to retain previous migrations.
261
+
262
+ Rails:
263
+
264
+ ```ruby
265
+ Lhm.cleanup(true, until: 1.day.ago)
266
+ ```
267
+
268
+ Ruby:
269
+
270
+ ```ruby
271
+ Lhm.cleanup(true, until: Time.now - 86400)
272
+ ```
273
+
274
+ ## Contributing
275
+
276
+ To run the tests:
277
+
278
+ ```bash
279
+ bundle exec rake unit # unit tests
280
+ bundle exec rake integration # integration tests
281
+ bundle exec rake unit # all tests
282
+ ```
283
+
284
+ You can run an individual test as follows:
285
+
286
+ ```bash
287
+ bundle exec rake unit TEST=spec/integration/atomic_switcher_spec.rb
288
+ ```
289
+
290
+ You can check the code coverage reporting for an individual test as follows:
291
+
292
+ ```bash
293
+ rm -rf coverage
294
+ COV=1 bundle exec rake unit TEST=spec/integration/atomic_switcher_spec.rb
295
+ open coverage/index.html
296
+ ```
297
+
298
+ To check the code coverage for all tests:
299
+
300
+ ```bash
301
+ rm -rf coverage
302
+ COV=1 bundle exec rake unit && bundle exec rake integration
303
+ open coverage/index.html
304
+ ```
305
+
306
+ ### Merging for a new version
307
+ When creating a PR for a new version, make sure that th version has been bumped in `lib/lhm/version.rb`. Then run the following code snippet to ensure the everything is consistent, otherwise
308
+ the gem will not publish.
309
+ ```bash
310
+ bundle install
311
+ bundle update
312
+ bundle exec appraisals install
313
+ ```
314
+
315
+ ### Docker Compose
316
+ The integration tests rely on a replication configuration for MySQL which is being proxied by an instance of ProxySQL.
317
+ It is important that every container is running to execute the integration test suite.
318
+
319
+ ## License
320
+
321
+ The license is included as [LICENSE](LICENSE) in this directory.
322
+
323
+ ## Similar solutions
324
+
325
+ * [OAK: online alter table][0]
326
+ * [Facebook][1]
327
+ * [Twitter][2]
328
+ * [pt-online-schema-change][3]
329
+
330
+ [0]: https://shlomi-noach.github.io/openarkkit/introduction.html
331
+ [1]: http://www.facebook.com/note.php?note\_id=430801045932
332
+ [2]: https://github.com/freels/table_migrator
333
+ [3]: http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html
334
+ [4]: https://travis-ci.org/soundcloud/lhm
335
+ [5]: https://travis-ci.org/soundcloud/lhm.svg?branch=master
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rake/testtask'
2
+ require 'bundler'
3
+ require 'bundler/gem_tasks'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ Rake::TestTask.new('unit') do |t|
8
+ t.libs << 'lib'
9
+ t.libs << 'spec'
10
+ t.test_files = FileList['spec/unit/**/*_spec.rb']
11
+ t.verbose = true
12
+ end
13
+
14
+ Rake::TestTask.new('integration') do |t|
15
+ t.libs << 'lib'
16
+ t.libs << 'spec'
17
+ t.test_files = FileList['spec/integration/**/*_spec.rb']
18
+ t.verbose = true
19
+ end
20
+
21
+ Rake::TestTask.new('dev') do |t|
22
+ t.libs << 'lib'
23
+ t.libs << 'spec'
24
+
25
+ files = FileList.new('spec/test_helper.rb')
26
+ files.add(ENV["SINGLE_TEST"]) if ENV["SINGLE_TEST"]
27
+ t.test_files = files
28
+
29
+ t.verbose = true
30
+ end
31
+
32
+ task :specs => [:unit, :integration]
33
+ task :default => :specs
data/dev.yml ADDED
@@ -0,0 +1,45 @@
1
+ name: lhm
2
+ up:
3
+ - homebrew:
4
+ - mysql-client@5.7:
5
+ or: [mysql@5.7]
6
+ conflicts: [shopify/shopify/mysql-client, mysql-connector-c, mysql, mysql-client]
7
+ - wget
8
+ - ruby: 2.7.5
9
+ - bundler
10
+ - custom:
11
+ name: Get Appraisal gems
12
+ met?: bundle exec appraisal install
13
+ meet: ":"
14
+ - docker
15
+ - custom:
16
+ name: Docker Compose
17
+ met?: docker compose ls | grep -ioE -q "lhm.*running\(4\)"
18
+ meet: docker compose up -d
19
+ - custom:
20
+ name: Waiting for DBs to be operational
21
+ met?: ./scripts/helpers/wait-for-dbs.sh
22
+ meet: ":"
23
+
24
+ commands:
25
+ unit: bundle exec rake unit
26
+ int: bundle exec rake integration
27
+ test:
28
+ optional: file
29
+ aliases: [ t ]
30
+ run: |
31
+ if [[ $# -eq 0 ]]; then
32
+ bundle exec rake unit && bundle exec rake integration
33
+ else
34
+ SINGLE_TEST="$@" bundle exec rake dev
35
+ fi
36
+ appraisals: bundle exec appraisal rake specs
37
+ cov: rm -rf coverage; COV=1 bundle exec rake unit && bundle exec rake integration; open coverage/index.html
38
+ logs:
39
+ desc: "See the DB logs (ctrl-c + ctrl-c to exit)"
40
+ run: docker-compose logs -f
41
+ clear:
42
+ run: docker-compose rm -v -s -f && docker-compose up -d && ./scripts/helpers/wait-for-dbs.sh
43
+ pre-publish:
44
+ # Ensures all Gemfile.lock are sync with the new version in `lhm/version.rb` and runs appraisals
45
+ run: bundle install && bundle exec appraisal install && bundle exec appraisal rake specs
@@ -0,0 +1,60 @@
1
+ services:
2
+ # Writer
3
+ mysql-1:
4
+ container_name: mysql-1
5
+ image: percona:5.7
6
+ platform: linux/amd64
7
+ command:
8
+ --server-id=1
9
+ --log-bin
10
+ --log-slave-updates=ON
11
+ --gtid-mode=ON
12
+ --enforce-gtid-consistency=ON
13
+ --read-only=OFF
14
+ --max-connections=1000
15
+ hostname: 'mysql-1'
16
+ volumes:
17
+ - ./scripts/mysql/writer:/docker-entrypoint-initdb.d
18
+ environment:
19
+ MYSQL_ROOT_PASSWORD: password
20
+ MYSQL_HOST: mysql-1
21
+ ports:
22
+ - "33006:3306"
23
+ # Reader
24
+ mysql-2:
25
+ container_name: mysql-2
26
+ image: percona:5.7
27
+ platform: linux/amd64
28
+ command:
29
+ --server-id=2
30
+ --log-bin
31
+ --log-slave-updates=ON
32
+ --gtid-mode=ON
33
+ --enforce-gtid-consistency=ON
34
+ --read-only=ON
35
+ --max-connections=1000
36
+ hostname: 'mysql-2'
37
+ volumes:
38
+ - ./scripts/mysql/reader:/docker-entrypoint-initdb.d
39
+ environment:
40
+ MYSQL_ROOT_PASSWORD: password
41
+ MYSQL_HOST: mysql-2
42
+ ports:
43
+ - "33007:3306"
44
+ # Proxysql
45
+ proxysql:
46
+ container_name: proxysql
47
+ image: proxysql/proxysql:2.0.11
48
+ volumes:
49
+ - ./scripts/proxysql/proxysql.cnf:/etc/proxysql.cnf
50
+ command: "proxysql -c /etc/proxysql.cnf -f --idle-threads"
51
+ ports:
52
+ - "33005:3306"
53
+ - "6032:6032"
54
+ toxiproxy:
55
+ container_name: toxiproxy
56
+ image: "ghcr.io/shopify/toxiproxy"
57
+ ports:
58
+ - "8474:8474"
59
+ - "22220:22220"
60
+ - "22222:22222"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "5.2.6"
6
+ gem "simplecov", "0.18.5"
7
+ gem "docile", "1.3.5"
8
+
9
+ gemspec path: "../"
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ lhm-shopify (3.5.5)
5
+ retriable (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (5.2.6)
11
+ activesupport (= 5.2.6)
12
+ activerecord (5.2.6)
13
+ activemodel (= 5.2.6)
14
+ activesupport (= 5.2.6)
15
+ arel (>= 9.0)
16
+ activesupport (5.2.6)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ after_do (0.4.0)
22
+ appraisal (2.4.1)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ arel (9.0.0)
27
+ byebug (11.1.3)
28
+ concurrent-ruby (1.1.9)
29
+ docile (1.3.5)
30
+ i18n (1.8.11)
31
+ concurrent-ruby (~> 1.0)
32
+ minitest (5.14.4)
33
+ mocha (1.13.0)
34
+ mysql2 (0.5.3)
35
+ rake (13.0.6)
36
+ retriable (3.1.2)
37
+ simplecov (0.18.5)
38
+ docile (~> 1.1)
39
+ simplecov-html (~> 0.11)
40
+ simplecov-html (0.12.3)
41
+ thor (1.1.0)
42
+ thread_safe (0.3.6)
43
+ toxiproxy (2.0.0)
44
+ tzinfo (1.2.9)
45
+ thread_safe (~> 0.1)
46
+
47
+ PLATFORMS
48
+ arm64-darwin-21
49
+ x86_64-darwin-20
50
+
51
+ DEPENDENCIES
52
+ activerecord (= 5.2.6)
53
+ after_do
54
+ appraisal
55
+ byebug
56
+ docile (= 1.3.5)
57
+ lhm-shopify!
58
+ minitest
59
+ mocha
60
+ mysql2
61
+ rake
62
+ simplecov (= 0.18.5)
63
+ toxiproxy
64
+
65
+ BUNDLED WITH
66
+ 2.2.22
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "6.0.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ lhm-shopify (3.5.5)
5
+ retriable (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (6.0.0)
11
+ activesupport (= 6.0.0)
12
+ activerecord (6.0.0)
13
+ activemodel (= 6.0.0)
14
+ activesupport (= 6.0.0)
15
+ activesupport (6.0.0)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ zeitwerk (~> 2.1, >= 2.1.8)
21
+ after_do (0.4.0)
22
+ appraisal (2.4.1)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ byebug (11.1.3)
27
+ concurrent-ruby (1.1.9)
28
+ docile (1.4.0)
29
+ i18n (1.8.11)
30
+ concurrent-ruby (~> 1.0)
31
+ minitest (5.14.4)
32
+ mocha (1.13.0)
33
+ mysql2 (0.5.3)
34
+ rake (13.0.6)
35
+ retriable (3.1.2)
36
+ simplecov (0.21.2)
37
+ docile (~> 1.1)
38
+ simplecov-html (~> 0.11)
39
+ simplecov_json_formatter (~> 0.1)
40
+ simplecov-html (0.12.3)
41
+ simplecov_json_formatter (0.1.3)
42
+ thor (1.1.0)
43
+ thread_safe (0.3.6)
44
+ toxiproxy (2.0.0)
45
+ tzinfo (1.2.9)
46
+ thread_safe (~> 0.1)
47
+ zeitwerk (2.5.1)
48
+
49
+ PLATFORMS
50
+ arm64-darwin-21
51
+ x86_64-darwin-20
52
+ x86_64-linux
53
+
54
+ DEPENDENCIES
55
+ activerecord (= 6.0.0)
56
+ after_do
57
+ appraisal
58
+ byebug
59
+ lhm-shopify!
60
+ minitest
61
+ mocha
62
+ mysql2
63
+ rake
64
+ simplecov
65
+ toxiproxy
66
+
67
+ BUNDLED WITH
68
+ 2.2.22
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "6.1.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ lhm-shopify (3.5.5)
5
+ retriable (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (6.1.0)
11
+ activesupport (= 6.1.0)
12
+ activerecord (6.1.0)
13
+ activemodel (= 6.1.0)
14
+ activesupport (= 6.1.0)
15
+ activesupport (6.1.0)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ zeitwerk (~> 2.3)
21
+ after_do (0.4.0)
22
+ appraisal (2.4.1)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ byebug (11.1.3)
27
+ concurrent-ruby (1.1.9)
28
+ docile (1.4.0)
29
+ i18n (1.8.11)
30
+ concurrent-ruby (~> 1.0)
31
+ minitest (5.14.4)
32
+ mocha (1.13.0)
33
+ mysql2 (0.5.3)
34
+ rake (13.0.6)
35
+ retriable (3.1.2)
36
+ simplecov (0.21.2)
37
+ docile (~> 1.1)
38
+ simplecov-html (~> 0.11)
39
+ simplecov_json_formatter (~> 0.1)
40
+ simplecov-html (0.12.3)
41
+ simplecov_json_formatter (0.1.3)
42
+ thor (1.1.0)
43
+ toxiproxy (2.0.0)
44
+ tzinfo (2.0.4)
45
+ concurrent-ruby (~> 1.0)
46
+ zeitwerk (2.5.1)
47
+
48
+ PLATFORMS
49
+ arm64-darwin-21
50
+ x86_64-darwin-20
51
+ x86_64-linux
52
+
53
+ DEPENDENCIES
54
+ activerecord (= 6.1.0)
55
+ after_do
56
+ appraisal
57
+ byebug
58
+ lhm-shopify!
59
+ minitest
60
+ mocha
61
+ mysql2
62
+ rake
63
+ simplecov
64
+ toxiproxy
65
+
66
+ BUNDLED WITH
67
+ 2.2.22