pg_easy_replicate 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f655d3bf7d458de6b84a85930e7175c05f780a390e9431531a0ae30c35d4737b
4
- data.tar.gz: fa23c33715823598d4795ba64cbf466088d01fd97315bfe97d3a05db2da50f48
3
+ metadata.gz: 8b855bf14bd72bcf4ace60b2f746139d76408d6a00e0ae7ec3fd2d0c276cf22b
4
+ data.tar.gz: 1eff23811d7e9d8608c241bcc7a67367c8de8271ea53d6960f57859aa5c186fd
5
5
  SHA512:
6
- metadata.gz: 1e69d89ca00ca077784aab0c042e46c85faf7e15f2e585a65321084c5b3543502a7c9a440faa17f829848015a31ed50393129a0d7bfa083a27a731af4c179b68
7
- data.tar.gz: ce29729ddcf74420818c0b4d86b98de28fbefd0690368ee4fcdd40f689dcf1ba6c3135850ab1e22de2bbd977c733ca5449cf42ccef728fda20c54b102b38f965
6
+ metadata.gz: a7de21167ee2027115972442b9aa859fba7954bdc2e04b8e27e92d6fbadd2e7c9eb92c700d01f69ba9fecd5b40fe5593b5d0467ba4b2766106a7951311401842
7
+ data.tar.gz: c38c45df66c9a4433b558a41f120f8c3304b5cbd9ea1072348df61397b7e51b38d1709b83c160917d69fbcf460e18dc9f9355ea7c96ae3d109ba40b4430ff06c
data/.rspec CHANGED
@@ -2,4 +2,4 @@
2
2
  --color
3
3
  --require spec_helper
4
4
  --fail-fast
5
- --exclude-pattern spec/lib/smoke_spec.rb
5
+ --exclude-pattern spec/smoke_spec.rb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.1.6] - 2023-06-22
2
+
3
+ - Bug fix: Support custom schema name
4
+ - New smoke spec in CI
5
+
6
+ ## [0.1.5] - 2023-06-22
7
+
8
+ - Fix bug in `stop_sync`
9
+
1
10
  ## [0.1.4] - 2023-06-22
2
11
 
3
12
  - Drop lockbox dependency
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pg_easy_replicate (0.1.5)
4
+ pg_easy_replicate (0.1.7)
5
5
  ougai (~> 2.0.0)
6
6
  pg (~> 1.5.3)
7
7
  sequel (~> 5.69.0)
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # pg_easy_replicate
2
2
 
3
3
  [![CI](https://github.com/shayonj/pg_easy_replicate/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/shayonj/pg_easy_replicate/actions/workflows/ci.yaml)
4
- [![Gem Version](https://badge.fury.io/rb/pg_easy_replicate.svg)](https://badge.fury.io/rb/pg_easy_replicate)
4
+ [![Smoke spec](https://github.com/shayonj/pg_easy_replicate/actions/workflows/smoke.yaml/badge.svg?branch=main)](https://github.com/shayonj/pg_easy_replicate/actions/workflows/ci.yaml)
5
+ [![Gem Version](https://badge.fury.io/rb/pg_easy_replicate.svg?1)](https://badge.fury.io/rb/pg_easy_replicate)
5
6
 
6
7
  `pg_easy_replicate` is a CLI orchestrator tool that simplifies the process of setting up [logical replication](https://www.postgresql.org/docs/current/logical-replication.html) between two PostgreSQL databases. `pg_easy_replicate` also supports switchover. After the source (primary database) is fully replicating, `pg_easy_replicate` puts it into read-only mode and via logical replication flushes all data to the new target database. This ensures zero data loss and minimal downtime for the application. This method can be useful for performing minimal downtime (up to <1min, depending) major version upgrades between two PostgreSQL databases, load testing with blue/green database setup and other similar use cases.
7
8
 
@@ -9,6 +9,14 @@ module PgEasyReplicate
9
9
  DEFAULT_WAIT = 5 # seconds
10
10
 
11
11
  def start_sync(options)
12
+ schema_name = options[:schema_name] || "public"
13
+ tables =
14
+ determine_tables(
15
+ schema: schema_name,
16
+ conn_string: source_db_url,
17
+ list: options[:tables],
18
+ )
19
+
12
20
  create_publication(
13
21
  group_name: options[:group_name],
14
22
  conn_string: source_db_url,
@@ -16,9 +24,9 @@ module PgEasyReplicate
16
24
 
17
25
  add_tables_to_publication(
18
26
  group_name: options[:group_name],
19
- tables: options[:tables],
27
+ tables: tables,
20
28
  conn_string: source_db_url,
21
- schema: options[:schema],
29
+ schema: schema_name,
22
30
  )
23
31
 
24
32
  create_subscription(
@@ -29,8 +37,8 @@ module PgEasyReplicate
29
37
 
30
38
  Group.create(
31
39
  name: options[:group_name],
32
- table_names: options[:tables],
33
- schema_name: options[:schema],
40
+ table_names: tables,
41
+ schema_name: schema_name,
34
42
  started_at: Time.now.utc,
35
43
  )
36
44
  rescue => e
@@ -45,8 +53,8 @@ module PgEasyReplicate
45
53
  else
46
54
  Group.create(
47
55
  name: options[:group_name],
48
- table_names: options[:tables],
49
- schema_name: options[:schema],
56
+ table_names: tables,
57
+ schema_name: schema_name,
50
58
  started_at: Time.now.utc,
51
59
  failed_at: Time.now.utc,
52
60
  )
@@ -80,19 +88,17 @@ module PgEasyReplicate
80
88
  "Adding tables up publication",
81
89
  { publication_name: publication_name(group_name) },
82
90
  )
83
- tables = tables&.split(",") || []
84
- unless tables.size > 0
85
- tables = list_all_tables(schema: schema, conn_string: conn_string)
86
- end
87
91
 
88
- tables.map do |table_name|
89
- Query.run(
90
- query:
91
- "ALTER PUBLICATION #{publication_name(group_name)} ADD TABLE \"#{table_name}\"",
92
- connection_url: conn_string,
93
- schema: schema,
94
- )
95
- end
92
+ tables
93
+ .split(",")
94
+ .map do |table_name|
95
+ Query.run(
96
+ query:
97
+ "ALTER PUBLICATION #{publication_name(group_name)} ADD TABLE \"#{table_name}\"",
98
+ connection_url: conn_string,
99
+ schema: schema,
100
+ )
101
+ end
96
102
  rescue => e
97
103
  raise "Unable to add tables to publication: #{e.message}"
98
104
  end
@@ -101,11 +107,12 @@ module PgEasyReplicate
101
107
  Query
102
108
  .run(
103
109
  query:
104
- "SELECT table_name FROM information_schema.tables WHERE table_schema = '#{schema}'",
110
+ "SELECT table_name FROM information_schema.tables WHERE table_schema = '#{schema}' ORDER BY table_name",
105
111
  connection_url: conn_string,
106
112
  )
107
113
  .map(&:values)
108
114
  .flatten
115
+ .join(",")
109
116
  end
110
117
 
111
118
  def drop_publication(group_name:, conn_string:)
@@ -197,11 +204,16 @@ module PgEasyReplicate
197
204
  group_name:,
198
205
  source_conn_string: source_db_url,
199
206
  target_conn_string: target_db_url,
200
- lag_delta_size: DEFAULT_LAG
207
+ lag_delta_size: nil
201
208
  )
202
209
  group = Group.find(group_name)
203
210
 
204
- watch_lag(group_name: group_name, lag: lag_delta_size)
211
+ run_vacuum_analyze(
212
+ conn_string: target_conn_string,
213
+ tables: group[:table_names],
214
+ schema: group[:schema_name],
215
+ )
216
+ watch_lag(group_name: group_name, lag: lag_delta_size || DEFAULT_LAG)
205
217
  revoke_connections_on_source_db(group_name)
206
218
  wait_for_remaining_catchup(group_name)
207
219
  refresh_sequences(
@@ -209,6 +221,12 @@ module PgEasyReplicate
209
221
  schema: group[:schema_name],
210
222
  )
211
223
  mark_switchover_complete(group_name)
224
+ # Run vacuum analyze to refresh the planner post switchover
225
+ run_vacuum_analyze(
226
+ conn_string: target_conn_string,
227
+ tables: group[:table_names],
228
+ schema: group[:schema_name],
229
+ )
212
230
  drop_subscription(
213
231
  group_name: group_name,
214
232
  target_conn_string: target_conn_string,
@@ -317,9 +335,39 @@ module PgEasyReplicate
317
335
  raise "Unable to refresh sequences: #{e.message}"
318
336
  end
319
337
 
338
+ def run_vacuum_analyze(conn_string:, tables:, schema:)
339
+ tables
340
+ .split(",")
341
+ .each do |t|
342
+ logger.info(
343
+ "Running vacuum analyze on #{t}",
344
+ schema: schema,
345
+ table: t,
346
+ )
347
+ Query.run(
348
+ query: "VACUUM VERBOSE ANALYZE #{t}",
349
+ connection_url: conn_string,
350
+ schema: schema,
351
+ transaction: false,
352
+ )
353
+ end
354
+ rescue => e
355
+ raise "Unable to run vacuum and analyze: #{e.message}"
356
+ end
357
+
320
358
  def mark_switchover_complete(group_name)
321
359
  Group.update(group_name: group_name, switchover_completed_at: Time.now)
322
360
  end
361
+
362
+ private
363
+
364
+ def determine_tables(schema:, conn_string:, list: "")
365
+ tables = list&.split(",") || []
366
+ unless tables.size > 0
367
+ return list_all_tables(schema: schema, conn_string: conn_string)
368
+ end
369
+ ""
370
+ end
323
371
  end
324
372
  end
325
373
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgEasyReplicate
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  end
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+
3
+ set -eo pipefail
4
+
5
+ if [[ -z ${GITHUB_WORKFLOW} ]]; then
6
+ export SECONDARY_SOURCE_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@source_db/postgres"
7
+ fi
8
+
9
+ export SOURCE_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@localhost:5432/postgres"
10
+ export TARGET_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@localhost:5433/postgres"
11
+ export PGPASSWORD='jamesbond123@7!'"'"'3aaR'
12
+
13
+ pgbench --initialize -s 5 --foreign-keys --host localhost -U jamesbond -d postgres
14
+
15
+ pg_dump --schema-only --host localhost -U jamesbond -d postgres >schema.sql
16
+ cat schema.sql | psql --host localhost -U jamesbond -d postgres -p 5433
17
+ rm schema.sql
18
+
19
+ bundle exec bin/pg_easy_replicate config_check
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ set -eo pipefail
4
+
5
+ if [[ -z ${GITHUB_WORKFLOW} ]]; then
6
+ export SECONDARY_SOURCE_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@source_db/postgres"
7
+ fi
8
+
9
+ export SOURCE_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@localhost:5432/postgres"
10
+ export TARGET_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@localhost:5433/postgres"
11
+ export PGPASSWORD='jamesbond123@7!'"'"''"'"'3aaR'
12
+
13
+ # Bootstrap and cleanup
14
+ echo "===== Performing Bootstrap and cleanup"
15
+ bundle exec bin/pg_easy_replicate bootstrap -g cluster-1
16
+ bundle exec bin/pg_easy_replicate start_sync -g cluster-1 -s public
17
+ bundle exec bin/pg_easy_replicate stats -g cluster-1
18
+ bundle exec bin/pg_easy_replicate switchover -g cluster-1
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_easy_replicate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shayon Mukherjee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-24 00:00:00.000000000 Z
11
+ date: 2023-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ougai
@@ -241,8 +241,6 @@ email:
241
241
  executables:
242
242
  - pg_easy_replicate
243
243
  - pg_easy_replicate_console
244
- - release.sh
245
- - test.sh
246
244
  extensions: []
247
245
  extra_rdoc_files: []
248
246
  files:
@@ -260,8 +258,6 @@ files:
260
258
  - Rakefile
261
259
  - bin/pg_easy_replicate
262
260
  - bin/pg_easy_replicate_console
263
- - bin/release.sh
264
- - bin/test.sh
265
261
  - docker-compose.yml
266
262
  - lib/pg_easy_replicate.rb
267
263
  - lib/pg_easy_replicate/cli.rb
@@ -272,6 +268,9 @@ files:
272
268
  - lib/pg_easy_replicate/stats.rb
273
269
  - lib/pg_easy_replicate/version.rb
274
270
  - package.json
271
+ - scripts/e2e-bootstrap.sh
272
+ - scripts/e2e-start.sh
273
+ - scripts/release.sh
275
274
  - yarn.lock
276
275
  homepage: https://github.com/shayonj/pg_easy_replicate
277
276
  licenses:
data/bin/test.sh DELETED
@@ -1,28 +0,0 @@
1
- #!/bin/bash
2
-
3
- set -euo pipefail
4
-
5
- export SECONDARY_SOURCE_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@source_db/postgres"
6
- export SOURCE_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@localhost:5432/postgres"
7
- export TARGET_DB_URL="postgres://jamesbond:jamesbond123%407%21%273aaR@localhost:5433/postgres"
8
-
9
- bundle exec bin/pg_easy_replicate config_check
10
-
11
- # Bootstrap and cleanup
12
- echo "===== Performing Bootstrap and cleanup"
13
- bundle exec bin/pg_easy_replicate bootstrap -g cluster-1
14
- bundle exec bin/pg_easy_replicate cleanup -e -g cluster-1
15
-
16
- # Bootstrap and start_sync
17
- echo "===== Performing Bootstrap, start_sync, stop_sync and cleanup"
18
- bundle exec bin/pg_easy_replicate bootstrap -g cluster-1
19
- bundle exec bin/pg_easy_replicate start_sync -g cluster-1
20
- bundle exec bin/pg_easy_replicate stop_sync -g cluster-1
21
- bundle exec bin/pg_easy_replicate cleanup -e -g cluster-1
22
-
23
- # Bootstrap with switchover
24
- echo "===== Performing Bootstrap, start_sync, stop_sync and cleanup"
25
- bundle exec bin/pg_easy_replicate bootstrap -g cluster-1
26
- bundle exec bin/pg_easy_replicate start_sync -g cluster-1
27
- # bundle exec bin/pg_easy_replicate switchover -g cluster-1
28
- bundle exec bin/pg_easy_replicate cleanup -e -g cluster-1
File without changes