pgoutput-client 0.2.3 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a375cce8bbb2d330974bfd22bdc0a7542c1c1ed5fe73f448e41bba717532aac2
4
- data.tar.gz: 3c20c8e182548d5556d4a8a503a92d2d8c89d5c926a59eaaf537812d4bb5cdca
3
+ metadata.gz: 9a0c63a95d0df00f5a4b8b5a0e85b01bbec1ed71688a41f853c065e2f2b01a03
4
+ data.tar.gz: 3e86b0d6e62c54c03edd73a86be9dce33997a60f2d5bd097459b3a2a0d75795a
5
5
  SHA512:
6
- metadata.gz: 78fc7ede75ae5fcd4b27adddef61d1f6b59ba8a26943bb44bf93d0dc5f2d97a477f36d12ec935fdf083792cbc8d37418e0b2a9f84fb7d14d15aa7e5847f8d2fd
7
- data.tar.gz: 58ea9e8475789846b3caad462fcfef693df07ad8ef9cf724e877f38ba2ca53a73b3e1476971a7b5b1c9ad47bb0b8c20fae2e31f47674a377bf03c7d09cb1533c
6
+ metadata.gz: 0577c07284f05bb0daa59ae055a39cdd456e2104f936c33b8a921473fb5554cf65dfae2f9d9d69ce82900e27dfb1a0f632c960654bae7526b73b62ab664f6007
7
+ data.tar.gz: e2ea5d853aee2079d280139f58f287063fc411e8ef846782c14b8f41c286bd1975027022ecfa395619f5494ce5622d640fc0a9b6bd1a0ca9a192ebbab5701d20
data/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.0 - 2026-07-17
6
+
7
+ ### Added
8
+
9
+ - Added `Runner#slot_status` and `SlotInspector` for version-tolerant
10
+ `pg_replication_slots` inspection.
11
+ - Added immutable `SlotStatus` snapshots exposing transport and slot-health
12
+ fields without imposing downstream recovery policy.
13
+
14
+ ## 0.2.4 - 2026-06-17
15
+
16
+ ### Added
17
+
18
+ - Added socket-aware replication stream polling.
19
+ - Added E2E coverage for PostgreSQL restart and replication stream recovery.
20
+ - Added connection readiness checks to E2E infrastructure.
21
+
22
+ ### Changed
23
+
24
+ - Improved replication stream handling during idle periods.
25
+ - Improved reconnect behavior after PostgreSQL restarts.
26
+ - Improved standby feedback reliability during long-running streams.
27
+ - Improved E2E test stability across PostgreSQL startup and restart scenarios.
28
+ - Normalized `PG#get_copy_data` idle responses to simplify stream processing.
29
+
30
+ ### Fixed
31
+
32
+ - Fixed replication stream recovery after PostgreSQL restart.
33
+ - Fixed handling of idle COPY stream reads.
34
+ - Fixed reconnect loops triggered by PostgreSQL replication timeouts.
35
+ - Fixed E2E race conditions during PostgreSQL initialization.
36
+ - Fixed replication slot creation behavior when a slot already exists.
37
+ - Fixed several edge cases uncovered by Mammoth integration testing.
38
+
39
+ ### Documentation
40
+
41
+ - Expanded YARD documentation coverage to 98.95%.
42
+
5
43
  ## 0.2.3 - 2026-06-17
6
44
 
7
45
  ### Fixed
data/README.md CHANGED
@@ -58,6 +58,7 @@ Decoded row events
58
58
  - Supports `CREATE_REPLICATION_SLOT`
59
59
  - Supports `DROP_REPLICATION_SLOT`
60
60
  - Supports `START_REPLICATION SLOT ... LOGICAL ...`
61
+ - Inspects version-dependent `pg_replication_slots` state
61
62
  - Parses XLogData envelopes
62
63
  - Parses primary keepalive messages
63
64
  - Builds standby feedback messages
@@ -175,6 +176,7 @@ It owns:
175
176
  - Keepalive handling
176
177
  - Standby status feedback
177
178
  - LSN conversion
179
+ - Replication-slot catalog inspection
178
180
 
179
181
  ---
180
182
 
@@ -241,6 +243,45 @@ client = Pgoutput::Client::Runner.new(...)
241
243
  client.start { |payload, metadata| ... }
242
244
  ```
243
245
 
246
+ Inspect the configured replication slot before applying a downstream recovery
247
+ policy:
248
+
249
+ ```ruby
250
+ status = client.slot_status
251
+
252
+ if status.nil?
253
+ warn "replication slot is missing"
254
+ else
255
+ puts status.restart_lsn
256
+ puts status.confirmed_flush_lsn
257
+ puts status.wal_status
258
+ puts status.invalidation_reason
259
+ end
260
+ ```
261
+
262
+ `SlotStatus` reflects the fields available on the connected PostgreSQL version.
263
+ Optional fields are `nil` on versions that do not expose them. The client
264
+ reports catalog state only; deciding whether a durable checkpoint is safe to
265
+ resume remains the downstream runtime's responsibility.
266
+
267
+ ### Pgoutput::Client::SlotInspector
268
+
269
+ Queries `pg_replication_slots` through a short-lived ordinary PostgreSQL
270
+ connection. `#fetch(slot_name)` returns `nil` when the slot is missing and a
271
+ `SlotStatus` snapshot otherwise. `Runner#slot_status` is the convenient entry
272
+ point for inspecting the runner's configured slot.
273
+
274
+ ### Pgoutput::Client::SlotStatus
275
+
276
+ Immutable replication-slot catalog snapshot. It exposes identity, activity,
277
+ WAL position, retention, and invalidation fields including:
278
+
279
+ - `slot_name`, `plugin`, `slot_type`, and `database`
280
+ - `active`, `active_pid`, and `inactive_since`
281
+ - `restart_lsn` and `confirmed_flush_lsn`
282
+ - `wal_status`, `safe_wal_size`, and `catalog_xmin`
283
+ - `conflicting` and `invalidation_reason`
284
+
244
285
  ### Pgoutput::Client::Configuration
245
286
 
246
287
  Immutable configuration object.
@@ -363,6 +404,62 @@ Equivalent Rake task:
363
404
  bundle exec rake e2e:run
364
405
  ```
365
406
 
407
+ ## Transport lifecycle behavior
408
+
409
+ `pgoutput-client` owns PostgreSQL logical replication transport and lifecycle
410
+ management. It opens the replication connection, optionally creates the logical
411
+ replication slot, starts streaming, sends standby status feedback, and retries
412
+ reconnectable failures.
413
+
414
+ ### Idle standby feedback
415
+
416
+ Long-running replication streams can be quiet for long periods when no WAL
417
+ changes are produced. During those idle periods the client wakes periodically
418
+ and sends standby status feedback so PostgreSQL does not terminate the walsender
419
+ for replication timeout.
420
+
421
+ Control the feedback cadence with `feedback_interval`:
422
+
423
+ ```ruby
424
+ runner = Pgoutput::Client::Runner.new(
425
+ database_url: ENV.fetch("DATABASE_URL"),
426
+ slot_name: "mammoth_live",
427
+ publication_names: ["mammoth_publication"],
428
+ feedback_interval: 10.0
429
+ )
430
+ ```
431
+
432
+ ### Idempotent automatic slot creation
433
+
434
+ When `auto_create_slot` is enabled, the client treats slot creation as
435
+ "ensure this slot exists". Missing slots are created before streaming; existing
436
+ slots are reused and do not cause startup failure.
437
+
438
+ ```ruby
439
+ runner = Pgoutput::Client::Runner.new(
440
+ database_url: ENV.fetch("DATABASE_URL"),
441
+ slot_name: "mammoth_live",
442
+ publication_names: ["mammoth_publication"],
443
+ auto_create_slot: true,
444
+ temporary_slot: false
445
+ )
446
+ ```
447
+
448
+ Existence alone does not prove that an existing or newly created slot can serve
449
+ a downstream durable checkpoint. Use `Runner#slot_status` to obtain catalog
450
+ state and apply continuity or recovery policy in the downstream runtime before
451
+ streaming.
452
+
453
+ Publication creation remains outside this gem. Create publications through
454
+ application migrations, database bootstrap SQL, or infrastructure tooling.
455
+
456
+ ### Restart recovery
457
+
458
+ After a stream has connected successfully, transient PostgreSQL outages are
459
+ retried through the reconnect lifecycle. This includes ordinary container or
460
+ process restart windows where PostgreSQL temporarily refuses connections or
461
+ reports that the database system is starting up.
462
+
366
463
  ---
367
464
 
368
465
  ## License
@@ -76,14 +76,19 @@ module Pgoutput
76
76
 
77
77
  # Receive one CopyData payload from the server.
78
78
  #
79
- # The call is non-blocking because the underlying `pg` call receives
80
- # `false` for its blocking argument. `nil` means no complete CopyData
81
- # payload is currently available.
79
+ # The stream must not block forever while PostgreSQL is idle, because the
80
+ # caller needs opportunities to send periodic standby feedback. Wait
81
+ # briefly for socket readability, then use the pg driver's blocking
82
+ # CopyData read only when data is available. `nil` means the stream is
83
+ # currently idle.
82
84
  #
83
85
  # @return [String, nil] raw CopyData payload or `nil`
84
86
  # @raise [ConnectionError] if receiving fails
85
87
  def get_copy_data # rubocop:disable Naming/AccessorMethodName
86
- @pg_connection.get_copy_data(false)
88
+ return nil unless copy_data_readable?
89
+
90
+ copy_data = @pg_connection.get_copy_data(false)
91
+ copy_data == false ? nil : copy_data
87
92
  rescue PG::Error => e
88
93
  raise ConnectionError, e.message
89
94
  end
@@ -110,6 +115,15 @@ module Pgoutput
110
115
 
111
116
  private
112
117
 
118
+ def copy_data_readable?
119
+ return true unless @pg_connection.respond_to?(:socket_io)
120
+
121
+ socket = @pg_connection.socket_io
122
+ return true unless socket
123
+
124
+ !!socket.wait_readable(0.1)
125
+ end
126
+
113
127
  def exec(sql)
114
128
  @pg_connection.exec(sql)
115
129
  rescue PG::Error => e
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Pgoutput
4
4
  module Client
5
+ # Internal immutable base class generated by `Data.define` for {Feedback}.
6
+ #
7
+ # @api private
5
8
  FeedbackData = Data.define(:received_lsn, :flushed_lsn, :applied_lsn, :client_clock, :reply_requested)
6
9
 
7
10
  # Standby status feedback message builder.
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Pgoutput
4
4
  module Client
5
+ # Internal immutable base class generated by `Data.define` for {Keepalive}.
6
+ #
7
+ # @api private
5
8
  KeepaliveData = Data.define(:wal_end, :server_clock, :reply_requested)
6
9
 
7
10
  # Immutable primary keepalive replication message.
@@ -37,7 +37,17 @@ module Pgoutput
37
37
  # @see Stream
38
38
  # @api public
39
39
  class Runner
40
+ # Default number of reconnect attempts after a previously healthy stream
41
+ # fails. The default is intentionally large enough to survive ordinary
42
+ # PostgreSQL restart windows.
43
+ #
44
+ # @return [Integer]
40
45
  DEFAULT_RECONNECT_ATTEMPTS = 30
46
+
47
+ # Base reconnect backoff, in seconds. Attempt `n` sleeps for
48
+ # `n * DEFAULT_RECONNECT_BACKOFF`.
49
+ #
50
+ # @return [Float]
41
51
  DEFAULT_RECONNECT_BACKOFF = 0.5
42
52
 
43
53
  # Configuration used by this runner.
@@ -60,6 +70,7 @@ module Pgoutput
60
70
  # {Configuration#initialize}
61
71
  # @return [void]
62
72
  # @raise [ConfigurationError] if the supplied configuration is invalid
73
+ # rubocop:disable Style/ArgumentsForwarding -- YARD needs a named parameter
63
74
  def initialize(**options)
64
75
  @configuration = Configuration.new(
65
76
  **options # : untyped
@@ -74,6 +85,7 @@ module Pgoutput
74
85
  @last_error = nil
75
86
  @reconnect_attempts = 0
76
87
  end
88
+ # rubocop:enable Style/ArgumentsForwarding
77
89
 
78
90
  # Start streaming raw pgoutput payloads.
79
91
  #
@@ -134,9 +146,9 @@ module Pgoutput
134
146
  #
135
147
  # @yield [payload, metadata] called once for each XLogData payload
136
148
  # @return [void]
137
- def restart(&block)
149
+ def restart(&)
138
150
  stop
139
- start(&block)
151
+ start(&)
140
152
  end
141
153
 
142
154
  # Whether the runner is currently inside its streaming loop.
@@ -191,6 +203,17 @@ module Pgoutput
191
203
  )
192
204
  end
193
205
 
206
+ # Inspect the configured replication slot through PostgreSQL's catalog.
207
+ #
208
+ # This reports transport state without applying downstream checkpoint or
209
+ # recovery policy.
210
+ #
211
+ # @return [SlotStatus, nil] current slot state, or `nil` when missing
212
+ # @raise [ConnectionError] when PostgreSQL cannot be queried
213
+ def slot_status
214
+ SlotInspector.new(database_url: configuration.database_url).fetch(configuration.slot_name)
215
+ end
216
+
194
217
  private
195
218
 
196
219
  def setup_connection(connection)
@@ -212,12 +235,12 @@ module Pgoutput
212
235
  error.message.match?(/replication slot .* already exists/i)
213
236
  end
214
237
 
215
- def run_stream_cycle(configuration, &block)
238
+ def run_stream_cycle(configuration, &)
216
239
  connection = Connection.open(configuration)
217
240
  setup_connection(connection)
218
241
  @connected_once = true
219
242
  @stream = Stream.new(connection:, configuration:, acked_lsn: @acked_lsn)
220
- @stream.start(&block)
243
+ @stream.start(&)
221
244
  :done
222
245
  rescue ConnectionError => e
223
246
  @last_error = e
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Pgoutput
6
+ module Client
7
+ # Reads PostgreSQL replication-slot catalog state.
8
+ #
9
+ # Inspection uses a short-lived ordinary database connection because
10
+ # catalog queries are separate from the long-lived replication protocol
11
+ # connection. Querying the whole catalog row through `to_jsonb` keeps the
12
+ # result compatible with PostgreSQL versions that expose different optional
13
+ # slot-health columns.
14
+ #
15
+ # @api public
16
+ class SlotInspector
17
+ # Version-tolerant catalog query for one replication slot.
18
+ #
19
+ # @return [String]
20
+ QUERY = <<~SQL
21
+ SELECT to_jsonb(slot) AS slot
22
+ FROM pg_catalog.pg_replication_slots AS slot
23
+ WHERE slot.slot_name = $1
24
+ SQL
25
+
26
+ # @return [String] PostgreSQL connection URL
27
+ attr_reader :database_url
28
+
29
+ # @param database_url [String] PostgreSQL connection URL
30
+ # @param connection_factory [#call, nil] optional connection factory for tests
31
+ def initialize(database_url:, connection_factory: nil)
32
+ @database_url = database_url
33
+ @connection_factory = connection_factory
34
+ end
35
+
36
+ # Fetch the configured slot's current catalog state.
37
+ #
38
+ # @param slot_name [String] replication slot name
39
+ # @return [SlotStatus, nil] snapshot, or `nil` when the slot is missing
40
+ # @raise [ConnectionError] when PostgreSQL cannot be queried
41
+ def fetch(slot_name)
42
+ connection = open_connection
43
+ row = connection.exec_params(QUERY, [String(slot_name)]).first
44
+ return nil unless row
45
+
46
+ SlotStatus.from_catalog(parse_catalog(row.fetch("slot")))
47
+ rescue pg_error_class => e
48
+ raise ConnectionError, e.message
49
+ ensure
50
+ connection&.close unless connection&.finished?
51
+ end
52
+
53
+ private
54
+
55
+ def open_connection
56
+ return @connection_factory.call(database_url) if @connection_factory
57
+
58
+ require "pg"
59
+ PG.connect(database_url)
60
+ end
61
+
62
+ def parse_catalog(value)
63
+ return value if value.is_a?(Hash)
64
+
65
+ JSON.parse(value)
66
+ end
67
+
68
+ def pg_error_class
69
+ require "pg"
70
+ PG::Error
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pgoutput
4
+ module Client
5
+ # Immutable snapshot of one PostgreSQL logical replication slot.
6
+ #
7
+ # Fields introduced by newer PostgreSQL versions are `nil` when the server
8
+ # does not expose them. The client reports transport/catalog state only;
9
+ # downstream runtimes remain responsible for deciding whether a checkpoint
10
+ # can safely resume from this slot.
11
+ #
12
+ # @api public
13
+ SlotStatusData = Data.define(
14
+ :slot_name,
15
+ :plugin,
16
+ :slot_type,
17
+ :database,
18
+ :active,
19
+ :active_pid,
20
+ :catalog_xmin,
21
+ :restart_lsn,
22
+ :confirmed_flush_lsn,
23
+ :wal_status,
24
+ :safe_wal_size,
25
+ :inactive_since,
26
+ :conflicting,
27
+ :invalidation_reason
28
+ )
29
+
30
+ # Typed replication-slot catalog snapshot.
31
+ #
32
+ # @api public
33
+ class SlotStatus < SlotStatusData
34
+ # Build a snapshot from a `pg_replication_slots` JSON object.
35
+ #
36
+ # @param attributes [Hash{String, Symbol=>Object}] catalog attributes
37
+ # @return [SlotStatus]
38
+ def self.from_catalog(attributes)
39
+ fetch = lambda do |key|
40
+ next attributes[key] if attributes.key?(key)
41
+
42
+ attributes[key.to_sym]
43
+ end
44
+
45
+ new(
46
+ slot_name: fetch.call("slot_name"),
47
+ plugin: fetch.call("plugin"),
48
+ slot_type: fetch.call("slot_type"),
49
+ database: fetch.call("database"),
50
+ active: fetch.call("active") == true,
51
+ active_pid: fetch.call("active_pid"),
52
+ catalog_xmin: fetch.call("catalog_xmin"),
53
+ restart_lsn: fetch.call("restart_lsn"),
54
+ confirmed_flush_lsn: fetch.call("confirmed_flush_lsn"),
55
+ wal_status: fetch.call("wal_status"),
56
+ safe_wal_size: fetch.call("safe_wal_size"),
57
+ inactive_since: fetch.call("inactive_since"),
58
+ conflicting: fetch.call("conflicting"),
59
+ invalidation_reason: fetch.call("invalidation_reason")
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Pgoutput
4
4
  module Client
5
+ # Internal immutable base class generated by `Data.define` for {RunnerState}.
6
+ #
7
+ # @api private
5
8
  RunnerStateData = Data.define(
6
9
  :running,
7
10
  :stop_requested,
@@ -71,7 +71,7 @@ module Pgoutput
71
71
  # @raise [ProtocolError] if an unknown or malformed replication message is
72
72
  # received
73
73
  # @raise [ConnectionError] if standby feedback cannot be sent
74
- def start(&block)
74
+ def start(&)
75
75
  raise ArgumentError, "block required" unless block_given?
76
76
 
77
77
  @running = true
@@ -83,7 +83,7 @@ module Pgoutput
83
83
  next
84
84
  end
85
85
 
86
- process_copy_data(copy_data, &block)
86
+ process_copy_data(copy_data, &)
87
87
  send_periodic_feedback
88
88
  end
89
89
  ensure
@@ -5,6 +5,6 @@ module Pgoutput
5
5
  # Current pgoutput-client gem version.
6
6
  #
7
7
  # @return [String]
8
- VERSION = "0.2.3"
8
+ VERSION = "0.3.0"
9
9
  end
10
10
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Pgoutput
4
4
  module Client
5
+ # Internal immutable base class generated by `Data.define` for {XLogData}.
6
+ #
7
+ # @api private
5
8
  ReplicationXLogData = Data.define(:wal_start, :wal_end, :server_clock, :payload)
6
9
 
7
10
  # Immutable XLogData replication envelope.
@@ -8,11 +8,20 @@ require_relative "client/xlog_data"
8
8
  require_relative "client/keepalive"
9
9
  require_relative "client/feedback"
10
10
  require_relative "client/state"
11
+ require_relative "client/slot_status"
12
+ require_relative "client/slot_inspector"
11
13
  require_relative "client/commands"
12
14
  require_relative "client/connection"
13
15
  require_relative "client/stream"
14
16
  require_relative "client/runner"
15
17
 
18
+ # Namespace for PostgreSQL pgoutput logical replication components.
19
+ #
20
+ # The top-level namespace is shared by pgoutput ecosystem gems. This gem
21
+ # defines only the `Pgoutput::Client` transport namespace and leaves protocol
22
+ # parsing, value decoding, and CDC normalization to sibling libraries.
23
+ #
24
+ # @api public
16
25
  module Pgoutput
17
26
  # Namespace for PostgreSQL logical replication transport support.
18
27
  #
data/sig/json.rbs ADDED
@@ -0,0 +1,3 @@
1
+ module JSON
2
+ def self.parse: (String source) -> Hash[(String | Symbol), untyped]
3
+ end
@@ -61,9 +61,11 @@ module Pgoutput
61
61
 
62
62
  # Receive one CopyData payload from the server.
63
63
  #
64
- # The call is non-blocking because the underlying `pg` call receives
65
- # `false` for its blocking argument. `nil` means no complete CopyData
66
- # payload is currently available.
64
+ # The stream must not block forever while PostgreSQL is idle, because the
65
+ # caller needs opportunities to send periodic standby feedback. Wait
66
+ # briefly for socket readability, then use the pg driver's blocking
67
+ # CopyData read only when data is available. `nil` means the stream is
68
+ # currently idle.
67
69
  #
68
70
  # @return [String, nil] raw CopyData payload or `nil`
69
71
  # @raise [ConnectionError] if receiving fails
@@ -85,6 +87,8 @@ module Pgoutput
85
87
 
86
88
  private
87
89
 
90
+ def copy_data_readable?: () -> bool
91
+
88
92
  def exec: (untyped sql) -> untyped
89
93
  end
90
94
  end
@@ -79,6 +79,8 @@ module Pgoutput
79
79
 
80
80
  def monitor: () -> Pgoutput::Client::RunnerState
81
81
 
82
+ def slot_status: () -> (Pgoutput::Client::SlotStatus | nil)
83
+
82
84
  private
83
85
 
84
86
  def setup_connection: (untyped connection) -> untyped
@@ -0,0 +1,18 @@
1
+ module Pgoutput
2
+ module Client
3
+ class SlotInspector
4
+ QUERY: String
5
+
6
+ attr_reader database_url: String
7
+
8
+ def initialize: (database_url: String, ?connection_factory: untyped) -> void
9
+ def fetch: (String slot_name) -> (SlotStatus | nil)
10
+
11
+ private
12
+
13
+ def open_connection: () -> untyped
14
+ def parse_catalog: (untyped value) -> Hash[(String | Symbol), untyped]
15
+ def pg_error_class: () -> singleton(::PG::Error)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,41 @@
1
+ module Pgoutput
2
+ module Client
3
+ class SlotStatusData < Data
4
+ attr_reader slot_name: String
5
+ attr_reader plugin: String?
6
+ attr_reader slot_type: String
7
+ attr_reader database: String?
8
+ attr_reader active: bool
9
+ attr_reader active_pid: Integer?
10
+ attr_reader catalog_xmin: String?
11
+ attr_reader restart_lsn: String?
12
+ attr_reader confirmed_flush_lsn: String?
13
+ attr_reader wal_status: String?
14
+ attr_reader safe_wal_size: Integer?
15
+ attr_reader inactive_since: String?
16
+ attr_reader conflicting: bool?
17
+ attr_reader invalidation_reason: String?
18
+
19
+ def self.new: (
20
+ slot_name: String,
21
+ plugin: String?,
22
+ slot_type: String,
23
+ database: String?,
24
+ active: bool,
25
+ active_pid: Integer?,
26
+ catalog_xmin: String?,
27
+ restart_lsn: String?,
28
+ confirmed_flush_lsn: String?,
29
+ wal_status: String?,
30
+ safe_wal_size: Integer?,
31
+ inactive_since: String?,
32
+ conflicting: bool?,
33
+ invalidation_reason: String?
34
+ ) -> instance
35
+ end
36
+
37
+ class SlotStatus < SlotStatusData
38
+ def self.from_catalog: (Hash[(String | Symbol), untyped] attributes) -> SlotStatus
39
+ end
40
+ end
41
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgoutput-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken C. Demanawa
@@ -53,11 +53,14 @@ files:
53
53
  - lib/pgoutput/client/keepalive.rb
54
54
  - lib/pgoutput/client/lsn.rb
55
55
  - lib/pgoutput/client/runner.rb
56
+ - lib/pgoutput/client/slot_inspector.rb
57
+ - lib/pgoutput/client/slot_status.rb
56
58
  - lib/pgoutput/client/state.rb
57
59
  - lib/pgoutput/client/stream.rb
58
60
  - lib/pgoutput/client/version.rb
59
61
  - lib/pgoutput/client/xlog_data.rb
60
62
  - lib/pgoutput_client.rb
63
+ - sig/json.rbs
61
64
  - sig/pg.rbs
62
65
  - sig/pgoutput/client/commands.rbs
63
66
  - sig/pgoutput/client/configuration.rbs
@@ -67,6 +70,8 @@ files:
67
70
  - sig/pgoutput/client/keepalive.rbs
68
71
  - sig/pgoutput/client/lsn.rbs
69
72
  - sig/pgoutput/client/runner.rbs
73
+ - sig/pgoutput/client/slot_inspector.rbs
74
+ - sig/pgoutput/client/slot_status.rbs
70
75
  - sig/pgoutput/client/state.rbs
71
76
  - sig/pgoutput/client/stream.rbs
72
77
  - sig/pgoutput/client/version.rbs