pgbus 0.13.1 → 0.13.3
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +78 -3
- data/app/models/pgbus/processed_event.rb +45 -0
- data/app/views/pgbus/dashboard/_queues_table.html.erb +5 -3
- data/app/views/pgbus/queues/_queues_list.html.erb +5 -3
- data/app/views/pgbus/queues/show.html.erb +3 -0
- data/config/locales/da.yml +7 -2
- data/config/locales/de.yml +7 -2
- data/config/locales/en.yml +7 -2
- data/config/locales/es.yml +7 -2
- data/config/locales/fi.yml +7 -2
- data/config/locales/fr.yml +7 -2
- data/config/locales/it.yml +7 -2
- data/config/locales/ja.yml +7 -2
- data/config/locales/nb.yml +7 -2
- data/config/locales/nl.yml +7 -2
- data/config/locales/pt.yml +7 -2
- data/config/locales/sv.yml +7 -2
- data/exe/pgbus-health +9 -0
- data/lib/generators/pgbus/add_processed_event_completion_generator.rb +45 -0
- data/lib/generators/pgbus/templates/add_processed_event_completion.rb.erb +19 -0
- data/lib/generators/pgbus/templates/migration.rb.erb +3 -0
- data/lib/pgbus/cli.rb +6 -4
- data/lib/pgbus/client.rb +44 -0
- data/lib/pgbus/configuration.rb +43 -0
- data/lib/pgbus/event_bus/handler.rb +49 -7
- data/lib/pgbus/generators/migration_detector.rb +13 -0
- data/lib/pgbus/health_probe.rb +132 -0
- data/lib/pgbus/integrations/appsignal/probe.rb +8 -4
- data/lib/pgbus/mcp/tools/queues_tool.rb +6 -0
- data/lib/pgbus/process/consumer.rb +4 -1
- data/lib/pgbus/process/readiness_snapshot.rb +30 -0
- data/lib/pgbus/process/supervisor.rb +64 -3
- data/lib/pgbus/process/worker.rb +14 -4
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source.rb +8 -1
- data/lib/pgbus/web/health_app.rb +23 -1
- data/lib/pgbus/web/metrics_serializer.rb +9 -0
- metadata +7 -1
|
@@ -44,6 +44,16 @@ module Pgbus
|
|
|
44
44
|
@pending_restarts = pending_restarts
|
|
45
45
|
@crash_counts = Hash.new(0)
|
|
46
46
|
@notify_hub = notify_hub
|
|
47
|
+
@intended_children = 0
|
|
48
|
+
@readiness = Concurrent::AtomicReference.new(
|
|
49
|
+
ReadinessSnapshot.new(booted: false, shutting_down: shutting_down, expected: 0, live: forks.size)
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The current container-local readiness state. Safe to call from any
|
|
54
|
+
# thread (the health server's accept thread reads it per probe).
|
|
55
|
+
def readiness_snapshot
|
|
56
|
+
@readiness.get
|
|
47
57
|
end
|
|
48
58
|
|
|
49
59
|
def shutting_down?
|
|
@@ -97,6 +107,7 @@ module Pgbus
|
|
|
97
107
|
start_notify_hub
|
|
98
108
|
|
|
99
109
|
boot_processes
|
|
110
|
+
mark_booted
|
|
100
111
|
monitor_loop
|
|
101
112
|
ensure
|
|
102
113
|
shutdown
|
|
@@ -105,17 +116,51 @@ module Pgbus
|
|
|
105
116
|
def graceful_shutdown
|
|
106
117
|
Pgbus.logger.info { "[Pgbus] Supervisor: graceful shutdown requested" }
|
|
107
118
|
@shutting_down = true
|
|
119
|
+
refresh_readiness
|
|
108
120
|
signal_children("TERM")
|
|
109
121
|
end
|
|
110
122
|
|
|
111
123
|
def immediate_shutdown
|
|
112
124
|
Pgbus.logger.warn { "[Pgbus] Supervisor: immediate shutdown requested" }
|
|
113
125
|
@shutting_down = true
|
|
126
|
+
refresh_readiness
|
|
114
127
|
signal_children("QUIT")
|
|
115
128
|
end
|
|
116
129
|
|
|
117
130
|
private
|
|
118
131
|
|
|
132
|
+
# Boot is complete: connection verified, queues bootstrapped, every
|
|
133
|
+
# configured child fork ATTEMPTED. The baseline is the larger of the
|
|
134
|
+
# intended-attempt count and the fork-table size: a boot-time fork
|
|
135
|
+
# failure (EAGAIN/ENOMEM, logged-and-swallowed in fork_*) leaves
|
|
136
|
+
# intended > live, so the readiness gate reports DEGRADED instead of
|
|
137
|
+
# blessing a container that is missing workers. Roles that legitimately
|
|
138
|
+
# declined to boot (scheduler with no recurring tasks) never reach a
|
|
139
|
+
# fork_* method and are counted by neither side.
|
|
140
|
+
def mark_booted
|
|
141
|
+
@booted = true
|
|
142
|
+
@expected_children = [@intended_children, @forks.size].max
|
|
143
|
+
refresh_readiness
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Count a child the configuration intends this boot to run. Called at
|
|
147
|
+
# the top of every fork_* method — before the fork can fail — and only
|
|
148
|
+
# pre-boot, so restart_child's re-forks never inflate the baseline.
|
|
149
|
+
def note_intended_child
|
|
150
|
+
@intended_children += 1 unless @booted
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Publish a fresh snapshot; the swapped-in Data is immutable, so the
|
|
154
|
+
# health server's accept thread always reads a consistent state.
|
|
155
|
+
def refresh_readiness
|
|
156
|
+
@readiness.set(
|
|
157
|
+
ReadinessSnapshot.new(
|
|
158
|
+
booted: !!@booted, shutting_down: @shutting_down,
|
|
159
|
+
expected: @expected_children || 0, live: @forks.size
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
end
|
|
163
|
+
|
|
119
164
|
# Log a single boot diagnostics banner: the settings that actually
|
|
120
165
|
# determine whether this deployment works. One consecutive block of
|
|
121
166
|
# "[Pgbus] boot:"-prefixed info lines so it reads cleanly under both the
|
|
@@ -253,6 +298,7 @@ module Pgbus
|
|
|
253
298
|
end
|
|
254
299
|
|
|
255
300
|
def fork_worker(worker_config, slot: nil)
|
|
301
|
+
note_intended_child
|
|
256
302
|
queues = worker_config[:queues] || [config.default_queue]
|
|
257
303
|
threads = worker_config[:threads] || 5
|
|
258
304
|
single_active = worker_config[:single_active_consumer] || false
|
|
@@ -337,6 +383,7 @@ module Pgbus
|
|
|
337
383
|
end
|
|
338
384
|
|
|
339
385
|
def fork_dispatcher
|
|
386
|
+
note_intended_child
|
|
340
387
|
pid = fork do
|
|
341
388
|
restore_signals
|
|
342
389
|
setup_child_process
|
|
@@ -364,6 +411,7 @@ module Pgbus
|
|
|
364
411
|
end
|
|
365
412
|
|
|
366
413
|
def fork_scheduler
|
|
414
|
+
note_intended_child
|
|
367
415
|
pid = fork do
|
|
368
416
|
restore_signals
|
|
369
417
|
setup_child_process
|
|
@@ -427,6 +475,7 @@ module Pgbus
|
|
|
427
475
|
end
|
|
428
476
|
|
|
429
477
|
def fork_consumer(consumer_config, slot: nil)
|
|
478
|
+
note_intended_child
|
|
430
479
|
# Array() so a consumer entry without :topics can't NoMethodError the
|
|
431
480
|
# supervisor on the topics.join log lines below.
|
|
432
481
|
topics = Array(consumer_config[:topics])
|
|
@@ -504,6 +553,7 @@ module Pgbus
|
|
|
504
553
|
end
|
|
505
554
|
|
|
506
555
|
def fork_outbox_poller
|
|
556
|
+
note_intended_child
|
|
507
557
|
pid = fork do
|
|
508
558
|
restore_signals
|
|
509
559
|
setup_child_process
|
|
@@ -537,6 +587,9 @@ module Pgbus
|
|
|
537
587
|
# refresh, and fork status broadcast (issue #381).
|
|
538
588
|
@notify_hub&.tick
|
|
539
589
|
end
|
|
590
|
+
# After reap + restarts so a clean recycle (reaped and re-forked in
|
|
591
|
+
# the same pass) never dips the published live count (issue #386).
|
|
592
|
+
refresh_readiness
|
|
540
593
|
interruptible_sleep(FORK_WAIT)
|
|
541
594
|
end
|
|
542
595
|
end
|
|
@@ -821,7 +874,12 @@ module Pgbus
|
|
|
821
874
|
def start_health_server
|
|
822
875
|
return unless config.health_port
|
|
823
876
|
|
|
824
|
-
|
|
877
|
+
# The standalone server answers /readyz from THIS supervisor's
|
|
878
|
+
# container-local snapshot — a rolling deploy's health gate must
|
|
879
|
+
# measure the new container, not the fleet-wide verdict a sibling
|
|
880
|
+
# container's workers can satisfy (issue #386).
|
|
881
|
+
app = Pgbus::Web::HealthApp.new(local_readiness: -> { readiness_snapshot })
|
|
882
|
+
@health_server = Pgbus::Web::HealthServer.new(port: config.health_port, bind: config.health_bind, app: app)
|
|
825
883
|
@health_server.start
|
|
826
884
|
end
|
|
827
885
|
|
|
@@ -876,8 +934,11 @@ module Pgbus
|
|
|
876
934
|
end
|
|
877
935
|
|
|
878
936
|
def shutdown
|
|
879
|
-
# Wait for
|
|
880
|
-
|
|
937
|
+
# Wait for children to drain and exit, bounded by config.shutdown_timeout
|
|
938
|
+
# (default drain_timeout + 5) so raising the drain window can never
|
|
939
|
+
# mean SIGKILLing workers mid-drain. An orchestrator's stop grace
|
|
940
|
+
# period should exceed this value (issue #386).
|
|
941
|
+
deadline = Time.now + config.shutdown_timeout
|
|
881
942
|
|
|
882
943
|
until @forks.empty? || Time.now > deadline
|
|
883
944
|
reap_children
|
data/lib/pgbus/process/worker.rb
CHANGED
|
@@ -155,6 +155,12 @@ module Pgbus
|
|
|
155
155
|
NOTIFY_RETRY_BASE_SECONDS = 5
|
|
156
156
|
NOTIFY_RETRY_MAX_SECONDS = 300
|
|
157
157
|
|
|
158
|
+
# Residual pool wait in #shutdown, AFTER the drain loop already spent up
|
|
159
|
+
# to config.drain_timeout on in-flight jobs. Short by design: a job still
|
|
160
|
+
# running has proven it won't finish, and this wait competes with the
|
|
161
|
+
# supervisor's shutdown_timeout deadline (issue #386).
|
|
162
|
+
POOL_TERMINATION_WAIT = 5
|
|
163
|
+
|
|
158
164
|
def run
|
|
159
165
|
setup_signals
|
|
160
166
|
start_heartbeat
|
|
@@ -175,9 +181,9 @@ module Pgbus
|
|
|
175
181
|
|
|
176
182
|
break if @lifecycle.stopped?
|
|
177
183
|
# quiesced? (all slots free), not idle? (any slot free) — exiting
|
|
178
|
-
# with work still in flight abandons those jobs to
|
|
179
|
-
#
|
|
180
|
-
#
|
|
184
|
+
# with work still in flight abandons those jobs to shutdown's short
|
|
185
|
+
# POOL_TERMINATION_WAIT residual. Bounded by config.drain_timeout so
|
|
186
|
+
# a stuck job can't wedge the loop forever.
|
|
181
187
|
break if @lifecycle.draining? && (@pool.quiesced? || drain_deadline_exceeded?)
|
|
182
188
|
|
|
183
189
|
claim_and_execute if @lifecycle.can_process?
|
|
@@ -792,7 +798,11 @@ module Pgbus
|
|
|
792
798
|
Pgbus.logger.info { "[Pgbus] Worker draining thread pool..." }
|
|
793
799
|
stop_wake_source
|
|
794
800
|
@pool.shutdown
|
|
795
|
-
|
|
801
|
+
# Residual wait only: the drain loop already waited up to
|
|
802
|
+
# config.drain_timeout for in-flight jobs. A job still running here has
|
|
803
|
+
# proven it won't finish; waiting another full window would push the
|
|
804
|
+
# worker past the supervisor's shutdown_timeout deadline (issue #386).
|
|
805
|
+
@pool.wait_for_termination(POOL_TERMINATION_WAIT)
|
|
796
806
|
@stat_buffer&.stop
|
|
797
807
|
@queue_lock&.unlock_all
|
|
798
808
|
@heartbeat&.stop
|
data/lib/pgbus/version.rb
CHANGED
|
@@ -1177,7 +1177,8 @@ module Pgbus
|
|
|
1177
1177
|
(SELECT EXTRACT(epoch FROM (NOW() - min(enqueued_at)))::int FROM pgmq.#{qtable}) AS oldest_msg_age_sec,
|
|
1178
1178
|
(SELECT CASE WHEN is_called THEN last_value ELSE 0 END FROM pgmq.#{seq_name}) AS total_messages,
|
|
1179
1179
|
(SELECT max(read_ct) FROM pgmq.#{qtable}) AS max_read_ct,
|
|
1180
|
-
(SELECT count(*) FROM pgmq.#{qtable} WHERE vt <= NOW() AND read_ct = 0) AS visible_unread_length
|
|
1180
|
+
(SELECT count(*) FROM pgmq.#{qtable} WHERE vt <= NOW() AND read_ct = 0) AS visible_unread_length,
|
|
1181
|
+
(SELECT EXTRACT(epoch FROM (NOW() - min(vt)))::int FROM pgmq.#{qtable} WHERE vt <= NOW()) AS oldest_claimable_age_sec
|
|
1181
1182
|
SQL
|
|
1182
1183
|
rescue StandardError => e
|
|
1183
1184
|
Pgbus.logger.debug { "[Pgbus::Web] Skipping queue metrics for #{name}: #{e.message}" }
|
|
@@ -1193,7 +1194,9 @@ module Pgbus
|
|
|
1193
1194
|
name: row["queue_name"],
|
|
1194
1195
|
queue_length: row["queue_length"].to_i,
|
|
1195
1196
|
queue_visible_length: row["queue_visible_length"].to_i,
|
|
1197
|
+
parked_length: row["queue_length"].to_i - row["queue_visible_length"].to_i,
|
|
1196
1198
|
oldest_msg_age_sec: row["oldest_msg_age_sec"]&.to_i,
|
|
1199
|
+
oldest_claimable_age_sec: row["oldest_claimable_age_sec"]&.to_i,
|
|
1197
1200
|
newest_msg_age_sec: row["newest_msg_age_sec"]&.to_i,
|
|
1198
1201
|
total_messages: row["total_messages"].to_i,
|
|
1199
1202
|
max_read_ct: row["max_read_ct"]&.to_i,
|
|
@@ -1216,6 +1219,7 @@ module Pgbus
|
|
|
1216
1219
|
count(CASE WHEN vt <= NOW() THEN 1 END) AS queue_visible_length,
|
|
1217
1220
|
EXTRACT(epoch FROM (NOW() - max(enqueued_at)))::int AS newest_msg_age_sec,
|
|
1218
1221
|
EXTRACT(epoch FROM (NOW() - min(enqueued_at)))::int AS oldest_msg_age_sec,
|
|
1222
|
+
EXTRACT(epoch FROM (NOW() - min(vt) FILTER (WHERE vt <= NOW())))::int AS oldest_claimable_age_sec,
|
|
1219
1223
|
max(read_ct) AS max_read_ct,
|
|
1220
1224
|
count(CASE WHEN vt <= NOW() AND read_ct = 0 THEN 1 END) AS visible_unread_length
|
|
1221
1225
|
FROM pgmq.#{qtable}
|
|
@@ -1229,6 +1233,7 @@ module Pgbus
|
|
|
1229
1233
|
q_summary.queue_visible_length,
|
|
1230
1234
|
q_summary.newest_msg_age_sec,
|
|
1231
1235
|
q_summary.oldest_msg_age_sec,
|
|
1236
|
+
q_summary.oldest_claimable_age_sec,
|
|
1232
1237
|
q_summary.max_read_ct,
|
|
1233
1238
|
q_summary.visible_unread_length,
|
|
1234
1239
|
all_metrics.total_messages
|
|
@@ -1241,7 +1246,9 @@ module Pgbus
|
|
|
1241
1246
|
name: queue_name,
|
|
1242
1247
|
queue_length: row["queue_length"].to_i,
|
|
1243
1248
|
queue_visible_length: row["queue_visible_length"].to_i,
|
|
1249
|
+
parked_length: row["queue_length"].to_i - row["queue_visible_length"].to_i,
|
|
1244
1250
|
oldest_msg_age_sec: row["oldest_msg_age_sec"]&.to_i,
|
|
1251
|
+
oldest_claimable_age_sec: row["oldest_claimable_age_sec"]&.to_i,
|
|
1245
1252
|
newest_msg_age_sec: row["newest_msg_age_sec"]&.to_i,
|
|
1246
1253
|
total_messages: row["total_messages"].to_i,
|
|
1247
1254
|
max_read_ct: row["max_read_ct"]&.to_i,
|
data/lib/pgbus/web/health_app.rb
CHANGED
|
@@ -49,8 +49,15 @@ module Pgbus
|
|
|
49
49
|
# @param data_source [Pgbus::Web::DataSource, nil] read layer for /readyz.
|
|
50
50
|
# nil (the default) builds a fresh DataSource per readiness check, which
|
|
51
51
|
# avoids serving stale metrics from a long-lived app's memoized instance.
|
|
52
|
-
|
|
52
|
+
# @param local_readiness [#call, nil] when set, /readyz answers from this
|
|
53
|
+
# callable's {Process::ReadinessSnapshot} instead of the cluster-wide
|
|
54
|
+
# analyzer — the supervisor's standalone HealthServer passes its own
|
|
55
|
+
# snapshot so a rolling deploy's health gate measures THIS container,
|
|
56
|
+
# not the fleet (issue #386). The Rails-mounted app leaves it nil and
|
|
57
|
+
# keeps the cluster verdict.
|
|
58
|
+
def initialize(data_source: nil, local_readiness: nil)
|
|
53
59
|
@data_source = data_source
|
|
60
|
+
@local_readiness = local_readiness
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
def call(env)
|
|
@@ -69,6 +76,8 @@ module Pgbus
|
|
|
69
76
|
end
|
|
70
77
|
|
|
71
78
|
def readyz
|
|
79
|
+
return local_readyz if @local_readiness
|
|
80
|
+
|
|
72
81
|
# HealthAnalyzer lives in the MCP namespace, which is excluded from
|
|
73
82
|
# Zeitwerk (its *tools* subclass the optional `mcp` gem). The analyzer
|
|
74
83
|
# itself has no gem dependency, so require just that one file — the
|
|
@@ -83,6 +92,19 @@ module Pgbus
|
|
|
83
92
|
[503, JSON_HEADERS.dup, [{ status: "ERROR", error: e.message }.to_json]]
|
|
84
93
|
end
|
|
85
94
|
|
|
95
|
+
# Container-local readiness: no database, no analyzer — just the
|
|
96
|
+
# supervisor's published snapshot. The error path mirrors the cluster
|
|
97
|
+
# readyz: 503 ERROR, logged, never swallowed.
|
|
98
|
+
def local_readyz
|
|
99
|
+
snapshot = @local_readiness.call
|
|
100
|
+
status = snapshot.ready? ? 200 : 503
|
|
101
|
+
body = { status: snapshot.status, expected: snapshot.expected, live: snapshot.live }
|
|
102
|
+
[status, JSON_HEADERS.dup, [body.to_json]]
|
|
103
|
+
rescue StandardError => e
|
|
104
|
+
Pgbus.logger.error { "[Pgbus::Web::HealthApp] local readiness check failed: #{e.class}: #{e.message}" }
|
|
105
|
+
[503, JSON_HEADERS.dup, [{ status: "ERROR", error: e.message }.to_json]]
|
|
106
|
+
end
|
|
107
|
+
|
|
86
108
|
# Reuse an injected DataSource (tests, an app that wants one shared
|
|
87
109
|
# instance); otherwise build a fresh one each check so per-instance
|
|
88
110
|
# memoization can never serve stale queue/process metrics.
|
|
@@ -54,6 +54,15 @@ module Pgbus
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
gauge(lines, "pgbus_queue_oldest_claimable_age_seconds",
|
|
58
|
+
"Age of the oldest message eligible for pickup (visibility timeout elapsed)") do
|
|
59
|
+
queues.filter_map do |q|
|
|
60
|
+
next unless q[:oldest_claimable_age_sec]
|
|
61
|
+
|
|
62
|
+
[q[:oldest_claimable_age_sec], { queue: q[:name] }]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
57
66
|
gauge(lines, "pgbus_queue_paused", "Whether the queue is paused (1) or active (0)") do
|
|
58
67
|
queues.map { |q| [q[:paused] ? 1 : 0, { queue: q[:name] }] }
|
|
59
68
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pgbus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.13.
|
|
4
|
+
version: 0.13.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mikael Henriksson
|
|
@@ -114,6 +114,7 @@ email:
|
|
|
114
114
|
- mikael@mhenrixon.com
|
|
115
115
|
executables:
|
|
116
116
|
- pgbus
|
|
117
|
+
- pgbus-health
|
|
117
118
|
extensions: []
|
|
118
119
|
extra_rdoc_files: []
|
|
119
120
|
files:
|
|
@@ -207,6 +208,7 @@ files:
|
|
|
207
208
|
- config/locales/sv.yml
|
|
208
209
|
- config/routes.rb
|
|
209
210
|
- exe/pgbus
|
|
211
|
+
- exe/pgbus-health
|
|
210
212
|
- lib/active_job/queue_adapters/pgbus_adapter.rb
|
|
211
213
|
- lib/generators/pgbus/add_failed_events_index_generator.rb
|
|
212
214
|
- lib/generators/pgbus/add_job_stats_generator.rb
|
|
@@ -214,6 +216,7 @@ files:
|
|
|
214
216
|
- lib/generators/pgbus/add_job_stats_queue_index_generator.rb
|
|
215
217
|
- lib/generators/pgbus/add_outbox_generator.rb
|
|
216
218
|
- lib/generators/pgbus/add_presence_generator.rb
|
|
219
|
+
- lib/generators/pgbus/add_processed_event_completion_generator.rb
|
|
217
220
|
- lib/generators/pgbus/add_queue_states_generator.rb
|
|
218
221
|
- lib/generators/pgbus/add_recurring_generator.rb
|
|
219
222
|
- lib/generators/pgbus/add_stream_queues_generator.rb
|
|
@@ -228,6 +231,7 @@ files:
|
|
|
228
231
|
- lib/generators/pgbus/templates/add_job_stats_queue_index.rb.erb
|
|
229
232
|
- lib/generators/pgbus/templates/add_outbox.rb.erb
|
|
230
233
|
- lib/generators/pgbus/templates/add_presence.rb.erb
|
|
234
|
+
- lib/generators/pgbus/templates/add_processed_event_completion.rb.erb
|
|
231
235
|
- lib/generators/pgbus/templates/add_queue_states.rb.erb
|
|
232
236
|
- lib/generators/pgbus/templates/add_recurring_tables.rb.erb
|
|
233
237
|
- lib/generators/pgbus/templates/add_stream_queues.rb.erb
|
|
@@ -282,6 +286,7 @@ files:
|
|
|
282
286
|
- lib/pgbus/failed_event_recorder.rb
|
|
283
287
|
- lib/pgbus/generators/database_target_detector.rb
|
|
284
288
|
- lib/pgbus/generators/migration_detector.rb
|
|
289
|
+
- lib/pgbus/health_probe.rb
|
|
285
290
|
- lib/pgbus/instrumentation.rb
|
|
286
291
|
- lib/pgbus/integrations/appsignal.rb
|
|
287
292
|
- lib/pgbus/integrations/appsignal/dashboard.json
|
|
@@ -333,6 +338,7 @@ files:
|
|
|
333
338
|
- lib/pgbus/process/notify_probe.rb
|
|
334
339
|
- lib/pgbus/process/primary_validator.rb
|
|
335
340
|
- lib/pgbus/process/queue_lock.rb
|
|
341
|
+
- lib/pgbus/process/readiness_snapshot.rb
|
|
336
342
|
- lib/pgbus/process/signal_handler.rb
|
|
337
343
|
- lib/pgbus/process/supervisor.rb
|
|
338
344
|
- lib/pgbus/process/wake_pipe.rb
|