pg_easy_replicate 0.1.6 → 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: ba133c0e80239fb125f32daa490fd20efe18c3f7391291d8465a8688fb3c0caf
4
- data.tar.gz: f5c1780f43b621ddf4a8359d7dd3131291f42fe064cbd131b1b49308f0bc041e
3
+ metadata.gz: 8b855bf14bd72bcf4ace60b2f746139d76408d6a00e0ae7ec3fd2d0c276cf22b
4
+ data.tar.gz: 1eff23811d7e9d8608c241bcc7a67367c8de8271ea53d6960f57859aa5c186fd
5
5
  SHA512:
6
- metadata.gz: b1d9e43d36d98b1cfe1e992123783f3adb160851acbc60447b77b7fba244dfbb1bf219686759b93619a9ac682813a24449bd4ddb3fea5c09f9990f6276b04ca9
7
- data.tar.gz: 68d31a389a1ff11a5e30bbe48b6ab9ebd746adf2a2787c18388627e08c8cd8c2dbaa289e1f898ab2a119b7da2a3e72df92a88a6826504c2438fa6a1cd6e7348e
6
+ metadata.gz: a7de21167ee2027115972442b9aa859fba7954bdc2e04b8e27e92d6fbadd2e7c9eb92c700d01f69ba9fecd5b40fe5593b5d0467ba4b2766106a7951311401842
7
+ data.tar.gz: c38c45df66c9a4433b558a41f120f8c3304b5cbd9ea1072348df61397b7e51b38d1709b83c160917d69fbcf460e18dc9f9355ea7c96ae3d109ba40b4430ff06c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.1.6] - 2023-06-22
2
+
3
+ - Bug fix: Support custom schema name
4
+ - New smoke spec in CI
5
+
1
6
  ## [0.1.5] - 2023-06-22
2
7
 
3
8
  - Fix bug in `stop_sync`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pg_easy_replicate (0.1.6)
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_name],
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_name],
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_name],
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
  )
@@ -81,19 +89,16 @@ module PgEasyReplicate
81
89
  { publication_name: publication_name(group_name) },
82
90
  )
83
91
 
84
- tables = tables&.split(",") || []
85
- unless tables.size > 0
86
- tables = list_all_tables(schema: schema, conn_string: conn_string)
87
- end
88
-
89
- tables.map do |table_name|
90
- Query.run(
91
- query:
92
- "ALTER PUBLICATION #{publication_name(group_name)} ADD TABLE \"#{table_name}\"",
93
- connection_url: conn_string,
94
- schema: schema,
95
- )
96
- 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
97
102
  rescue => e
98
103
  raise "Unable to add tables to publication: #{e.message}"
99
104
  end
@@ -102,11 +107,12 @@ module PgEasyReplicate
102
107
  Query
103
108
  .run(
104
109
  query:
105
- "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",
106
111
  connection_url: conn_string,
107
112
  )
108
113
  .map(&:values)
109
114
  .flatten
115
+ .join(",")
110
116
  end
111
117
 
112
118
  def drop_publication(group_name:, conn_string:)
@@ -202,6 +208,11 @@ module PgEasyReplicate
202
208
  )
203
209
  group = Group.find(group_name)
204
210
 
211
+ run_vacuum_analyze(
212
+ conn_string: target_conn_string,
213
+ tables: group[:table_names],
214
+ schema: group[:schema_name],
215
+ )
205
216
  watch_lag(group_name: group_name, lag: lag_delta_size || DEFAULT_LAG)
206
217
  revoke_connections_on_source_db(group_name)
207
218
  wait_for_remaining_catchup(group_name)
@@ -210,6 +221,12 @@ module PgEasyReplicate
210
221
  schema: group[:schema_name],
211
222
  )
212
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
+ )
213
230
  drop_subscription(
214
231
  group_name: group_name,
215
232
  target_conn_string: target_conn_string,
@@ -318,9 +335,39 @@ module PgEasyReplicate
318
335
  raise "Unable to refresh sequences: #{e.message}"
319
336
  end
320
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
+
321
358
  def mark_switchover_complete(group_name)
322
359
  Group.update(group_name: group_name, switchover_completed_at: Time.now)
323
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
324
371
  end
325
372
  end
326
373
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgEasyReplicate
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.7"
5
5
  end
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.6
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