wal 0.0.33 → 0.0.34

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: 79eda85dc0f833f81fc5c4778b7f8333559308f46111758e09977ec3dc98461c
4
- data.tar.gz: 470232c05cf0dc4ee5d55448ce6b88aa57373c53f504dda3526482a3473d3dbc
3
+ metadata.gz: f7a8f82addc9ffce03d2f1ee6a77bac1f3ae2074a5b427a8c60ca087df2aded6
4
+ data.tar.gz: 75559dccba1edf1d0f1a60ebf866726705fe48166d697a1859ec6da644e963f3
5
5
  SHA512:
6
- metadata.gz: e30d85d2e335ab143daa5de2962912009a340ba279ab47e4f531e6577ada0eb2cca22148f10601d75fc992bbb35cf8b081ebc02b698189d1ab4f841029367254
7
- data.tar.gz: 262104fb88bd6cb51ad181f9d8bea74e25d9f9798a5f04969ec33c29d71ccd9c9fb4cd22ba2b089075c5a4458d028597c5cfabe24a5086578bd297b67598be76
6
+ metadata.gz: 0d0d206e647386006b07e1a89e1a5596346a50894d0260d5def25876902abcbd398c07889a03ac43c88041343e576b2793eec8a1eecdcf47ff1f025587721a38
7
+ data.tar.gz: 62b2dbbeadf2c8076f2dee4ad1a95491552dfb0be3af646b03ffa449dd54009cfd940020fe4dfe3b69c2c5e7a707bdafdc2959baebe109ba28d288b31a086031
@@ -20,17 +20,18 @@ module Wal
20
20
  def on_event(event)
21
21
  case event
22
22
  when Wal::BeginTransactionEvent
23
- @start = Time.now
23
+ @start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
24
24
  @count = 0
25
- if event.estimated_size > 0
26
- Wal.logger&.debug("[#{@slot}] Begin transaction=#{event.transaction_id} size=#{event.estimated_size}")
27
- end
25
+ Wal.logger&.debug("[#{@slot}] Begin transaction=#{event.transaction_id} size=#{event.estimated_size}")
28
26
  when Wal::CommitTransactionEvent
29
- if @count > 0
30
- elapsed = ((Time.now - @start) * 1000.0).round(1)
31
- actions = " actions=#{@actions.sort.join(",")}" unless @actions.empty?
32
- tables = " tables=#{@tables.sort.join(",")}" unless @tables.empty?
33
- Wal.logger&.info("[#{@slot}] Commit transaction=#{event.transaction_id} elapsed=#{elapsed} events=#{@count}#{actions}#{tables}")
27
+ elapsed = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - @start) * 1000).round(3)
28
+ message = "[#{@slot}] Commit transaction=#{event.transaction_id} elapsed=#{elapsed} events=#{@count}"
29
+ message << " actions=#{@actions.sort.join(",")}" unless @actions.empty?
30
+ message << " tables=#{@tables.sort.join(",")}" unless @tables.empty?
31
+ if @count > 1
32
+ Wal.logger&.info(message)
33
+ else
34
+ Wal.logger&.debug(message)
34
35
  end
35
36
  @actions.clear
36
37
  @tables.clear
@@ -40,7 +41,11 @@ module Wal
40
41
  @actions << :insert
41
42
  @tables << event.table
42
43
  when Wal::UpdateEvent
43
- Wal.logger&.debug("[#{@slot}] Update transaction=#{event.transaction_id} table=#{event.table} primary_key=#{event.primary_key}")
44
+ if Wal.logger&.level >= Logger::DEBUG
45
+ message = "[#{@slot}] Update transaction=#{event.transaction_id} table=#{event.table} primary_key=#{event.primary_key}"
46
+ message << " changed=#{event.diff.keys.join(",")}" if event.diff && !event.diff.empty?
47
+ Wal.logger&.debug(message)
48
+ end
44
49
  @count += 1
45
50
  @actions << :update
46
51
  @tables << event.table
data/lib/wal/runner.rb CHANGED
@@ -32,30 +32,38 @@ module Wal
32
32
  Thread.new(slot, watcher, temporary, publications) do |replication_slot, watcher, use_temporary_slot, publications|
33
33
  retries = 0
34
34
  replication_slot = "#{replication_slot}_#{SecureRandom.alphanumeric(4)}" if use_temporary_slot
35
- puts "Watcher started for #{replication_slot} slot (#{publications.join(", ")})"
35
+ puts "[#{replication_slot}] Watcher started for #{replication_slot} slot (#{publications.join(", ")})"
36
36
 
37
37
  begin
38
+ Wal.hooks[:on_slot_start]&.call(slot, config)
39
+
38
40
  replicator_class
39
41
  .new(db_config:, **replicator_params, replication_slot:, use_temporary_slot:)
40
42
  .replicate_forever(Wal::LoggingWatcher.new(replication_slot, watcher), publications:)
43
+
44
+ Wal.hooks[:on_slot_finish]&.call(slot, config)
45
+
41
46
  if auto_restart
42
47
  backoff_time = backoff_exponent ? (backoff * retries) ** backoff_exponent : backoff
43
- puts "Watcher finished for #{replication_slot}, auto restarting in #{backoff_time.floor(2)}..."
48
+ puts "[#{replication_slot}] Watcher finished for #{replication_slot}, auto restarting in #{backoff_time.floor(2)}..."
44
49
  sleep backoff_time
45
- puts "Restarting #{replication_slot}"
50
+ puts "[#{replication_slot}] Restarting"
46
51
  redo
47
52
  end
48
53
  rescue ArgumentError
49
54
  raise
50
55
  rescue StandardError => err
56
+ Wal.hooks[:on_slot_error]&.call(err, slot, config)
57
+
58
+ Wal.logger&.error("[#{replication_slot}] Error #{err}")
59
+ Wal.logger&.error([err.message, *err.backtrace].join("\n"))
60
+
51
61
  if retries < max_retries
52
- Wal.logger&.error("[#{replication_slot}] Error #{err}")
53
- Wal.logger&.error([err.message, *err.backtrace].join("\n"))
54
62
  retries += 1
55
63
  backoff_time = backoff_exponent ? (backoff * retries) ** backoff_exponent : backoff
56
- puts "Restarting #{replication_slot} in #{backoff_time.floor(2)}s..."
64
+ puts "#{replication_slot}] Restarting #{replication_slot} in #{backoff_time.floor(2)}s..."
57
65
  sleep backoff_time
58
- puts "Restarting #{replication_slot}"
66
+ puts "#{replication_slot}] Restarting #{replication_slot}"
59
67
  retry
60
68
  end
61
69
  raise
@@ -105,12 +113,12 @@ module Wal
105
113
  end
106
114
 
107
115
  def run_forked_workers(workers_slots)
108
- Wal.fork_hooks[:before_fork]&.call
116
+ Wal.hooks[:before_fork]&.call(workers_slots)
109
117
 
110
118
  workers_slots.each do |worker_name, slot_configs|
111
119
  pid = fork_worker(worker_name, slot_configs)
112
120
  @child_pids << pid
113
- puts "Spawned worker '#{worker_name}' with PID #{pid}"
121
+ puts "[#{worker_name}] Spawned worker '#{worker_name}' with PID #{pid}"
114
122
  end
115
123
 
116
124
  @ping_thread = start_ping_thread
@@ -122,7 +130,7 @@ module Wal
122
130
 
123
131
  def fork_worker(worker_name, slot_configs)
124
132
  Process.fork do
125
- Wal.fork_hooks[:after_fork]&.call
133
+ Wal.hooks[:after_fork]&.call(worker_name, slot_configs)
126
134
  puts "[#{worker_name}] Starting worker process (PID: #{Process.pid})"
127
135
  worker = Worker.new(name: worker_name, slot_configs: slot_configs, db_config: db_config)
128
136
  worker.run
data/lib/wal/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wal
4
- VERSION = "0.0.33"
4
+ VERSION = "0.0.34"
5
5
  end
data/lib/wal.rb CHANGED
@@ -16,22 +16,30 @@ require_relative "wal/version"
16
16
  module Wal
17
17
  class << self
18
18
  attr_accessor :logger
19
- attr_accessor :fork_hooks
19
+ attr_accessor :hooks
20
20
 
21
21
  def logger
22
22
  @logger ||= Logger.new($stdout, level: :info)
23
23
  end
24
24
 
25
- def fork_hooks
26
- @fork_hooks ||= {}
25
+ def hooks
26
+ @hooks ||= {}
27
+ end
28
+
29
+ def on_slot_finished(&block)
30
+ hooks[:on_slot_finished] = block
31
+ end
32
+
33
+ def on_slot_error(&block)
34
+ hooks[:on_slot_error] = block
27
35
  end
28
36
 
29
37
  def before_fork(&block)
30
- fork_hooks[:before_fork] = block
38
+ hooks[:before_fork] = block
31
39
  end
32
40
 
33
41
  def after_fork(&block)
34
- fork_hooks[:after_fork] = block
42
+ hooks[:after_fork] = block
35
43
  end
36
44
  end
37
45
 
data/rbi/wal.rbi CHANGED
@@ -7,17 +7,26 @@ module Wal
7
7
  UpdateEvent,
8
8
  DeleteEvent,
9
9
  ) }
10
- VERSION = "0.0.33"
10
+ VERSION = "0.0.34"
11
11
 
12
12
  class << self
13
13
  sig { returns(T.class_of(Logger)) }
14
14
  attr_accessor :logger
15
15
 
16
- sig { params(block: T.proc.void).void }
16
+ sig { params(block: T.proc.params(worker_name: T.untyped).void).void }
17
17
  def before_fork(&block); end
18
18
 
19
- sig { params(block: T.proc.void).void }
19
+ sig { params(block: T.proc.params(worker_name: String, slot_configs: T.untyped).void).void }
20
20
  def after_fork(&block); end
21
+
22
+ sig { params(block: T.proc.params(slot: String, config: T.untyped).void).void }
23
+ def on_slot_start(&block); end
24
+
25
+ sig { params(block: T.proc.params(error: StandardError, slot: String, config: T.untyped).void).void }
26
+ def on_slot_error(&block); end
27
+
28
+ sig { params(block: T.proc.params(slot: String, config: T.untyped).void).void }
29
+ def on_slot_finish(&block); end
21
30
  end
22
31
 
23
32
  sig { params(block: T.proc.params(config: T.class_of(Wal)).void).void }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.33
4
+ version: 0.0.34
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Navarro
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-02-09 00:00:00.000000000 Z
10
+ date: 2026-02-11 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: pg