pgbus 0.5.1 → 0.6.1
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/README.md +244 -1
- data/Rakefile +8 -1
- data/app/controllers/pgbus/insights_controller.rb +6 -0
- data/app/helpers/pgbus/streams_helper.rb +115 -0
- data/app/javascript/pgbus/stream_source_element.js +212 -0
- data/app/models/pgbus/stream_stat.rb +123 -0
- data/app/views/pgbus/insights/show.html.erb +59 -0
- data/config/locales/en.yml +16 -0
- data/config/routes.rb +11 -0
- data/lib/generators/pgbus/add_job_stats_queue_index_generator.rb +53 -0
- data/lib/generators/pgbus/add_presence_generator.rb +55 -0
- data/lib/generators/pgbus/add_stream_stats_generator.rb +54 -0
- data/lib/generators/pgbus/templates/add_job_stats_latency.rb.erb +4 -1
- data/lib/generators/pgbus/templates/add_job_stats_queue_index.rb.erb +11 -0
- data/lib/generators/pgbus/templates/add_presence.rb.erb +26 -0
- data/lib/generators/pgbus/templates/add_stream_stats.rb.erb +18 -0
- data/lib/generators/pgbus/update_generator.rb +176 -23
- data/lib/pgbus/client/ensure_stream_queue.rb +54 -0
- data/lib/pgbus/client/read_after.rb +100 -0
- data/lib/pgbus/client.rb +6 -0
- data/lib/pgbus/configuration.rb +65 -0
- data/lib/pgbus/engine.rb +31 -0
- data/lib/pgbus/generators/config_converter.rb +22 -2
- data/lib/pgbus/generators/database_target_detector.rb +94 -0
- data/lib/pgbus/generators/migration_detector.rb +217 -0
- data/lib/pgbus/process/dispatcher.rb +62 -4
- data/lib/pgbus/streams/cursor.rb +71 -0
- data/lib/pgbus/streams/envelope.rb +58 -0
- data/lib/pgbus/streams/filters.rb +98 -0
- data/lib/pgbus/streams/presence.rb +216 -0
- data/lib/pgbus/streams/signed_name.rb +69 -0
- data/lib/pgbus/streams/turbo_broadcastable.rb +53 -0
- data/lib/pgbus/streams/watermark_cache_middleware.rb +28 -0
- data/lib/pgbus/streams.rb +151 -0
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source.rb +88 -10
- data/lib/pgbus/web/stream_app.rb +179 -0
- data/lib/pgbus/web/streamer/connection.rb +122 -0
- data/lib/pgbus/web/streamer/dispatcher.rb +467 -0
- data/lib/pgbus/web/streamer/heartbeat.rb +105 -0
- data/lib/pgbus/web/streamer/instance.rb +176 -0
- data/lib/pgbus/web/streamer/io_writer.rb +73 -0
- data/lib/pgbus/web/streamer/listener.rb +228 -0
- data/lib/pgbus/web/streamer/registry.rb +103 -0
- data/lib/pgbus/web/streamer.rb +53 -0
- data/lib/pgbus.rb +28 -0
- data/lib/puma/plugin/pgbus_streams.rb +54 -0
- data/lib/tasks/pgbus_streams.rake +52 -0
- metadata +33 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "puma/plugin"
|
|
4
|
+
|
|
5
|
+
# Puma plugin that tears down the pgbus Streamer cleanly on worker
|
|
6
|
+
# shutdown (SIGTERM, SIGUSR2 phased restart, SIGINT). Without this
|
|
7
|
+
# hook, Puma closes hijacked SSE sockets abruptly during shutdown,
|
|
8
|
+
# which looks to the browser like a network error and causes an
|
|
9
|
+
# immediate reconnect attempt mid-deploy. With the hook, the Streamer
|
|
10
|
+
# writes a `pgbus:shutdown` sentinel event to each connection and
|
|
11
|
+
# closes them cleanly, and clients reconnect to the new worker via
|
|
12
|
+
# EventSource's built-in Last-Event-ID mechanism — picking up any
|
|
13
|
+
# messages that landed during the flip via the PGMQ archive replay path.
|
|
14
|
+
#
|
|
15
|
+
# Users opt in by adding `plugin :pgbus_streams` to their puma.rb:
|
|
16
|
+
#
|
|
17
|
+
# # config/puma.rb
|
|
18
|
+
# plugin :pgbus_streams
|
|
19
|
+
#
|
|
20
|
+
# Auto-registering at gem load time would be too magical and would
|
|
21
|
+
# break users who aren't running Puma (e.g. the gem also ships a CLI
|
|
22
|
+
# and a non-Rails use case). Explicit opt-in is safer.
|
|
23
|
+
Puma::Plugin.create do
|
|
24
|
+
def start(launcher)
|
|
25
|
+
launcher.events.register(:after_stopped) do
|
|
26
|
+
teardown_streamer(launcher)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
launcher.events.register(:before_restart) do
|
|
30
|
+
teardown_streamer(launcher)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def teardown_streamer(launcher)
|
|
35
|
+
return unless defined?(Pgbus::Web::Streamer)
|
|
36
|
+
|
|
37
|
+
# Go through the public API so `@current_mutex` guards both the
|
|
38
|
+
# read and the clear. Bypassing it with instance_variable_get/set
|
|
39
|
+
# would race with any thread that's currently inside
|
|
40
|
+
# `Streamer.current` building a new Instance.
|
|
41
|
+
Pgbus::Web::Streamer.reset!
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
log_error(launcher, e)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def log_error(launcher, error)
|
|
47
|
+
message = "[Pgbus::Puma::Plugin] streamer teardown raised: #{error.class}: #{error.message}"
|
|
48
|
+
if launcher.respond_to?(:log_writer)
|
|
49
|
+
launcher.log_writer.log(message)
|
|
50
|
+
elsif defined?(Pgbus) && Pgbus.respond_to?(:logger)
|
|
51
|
+
Pgbus.logger.warn { message }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :pgbus do
|
|
4
|
+
namespace :streams do
|
|
5
|
+
desc "Fail if any pgbus controller or web component includes ActionController::Live"
|
|
6
|
+
task :lint_no_live do
|
|
7
|
+
# ActionController::Live has well-documented interactions with Puma
|
|
8
|
+
# that tie up worker threads for the lifetime of a streaming response
|
|
9
|
+
# (puma/puma#1009, puma/puma#938, puma/puma#569, rails/rails#10948).
|
|
10
|
+
# The pgbus streams subsystem is built on rack.hijack specifically to
|
|
11
|
+
# avoid this class of bug — hijack releases the worker thread as long
|
|
12
|
+
# as the Rack code returns promptly after hijacking. Any accidental
|
|
13
|
+
# reintroduction of ActionController::Live into the pgbus web layer
|
|
14
|
+
# would regress the architecture invisibly, so we guard against it
|
|
15
|
+
# in CI.
|
|
16
|
+
# The host app's Pgbus-namespaced controllers live under
|
|
17
|
+
# Rails.root/app/controllers/pgbus. The gem's own streaming
|
|
18
|
+
# code lives under gem_root/lib/pgbus/web. __dir__ here is
|
|
19
|
+
# gem_root/lib/tasks, which is why the app path needs
|
|
20
|
+
# Rails.root (or Dir.pwd when this task runs outside a Rails
|
|
21
|
+
# context) — resolving `app/controllers/pgbus` from __dir__
|
|
22
|
+
# would silently lint the gem itself and miss every consumer
|
|
23
|
+
# app's overrides.
|
|
24
|
+
app_root = defined?(Rails) && Rails.respond_to?(:root) ? Rails.root.to_s : Dir.pwd
|
|
25
|
+
roots = [
|
|
26
|
+
File.expand_path("app/controllers/pgbus", app_root),
|
|
27
|
+
File.expand_path("../pgbus/web", __dir__)
|
|
28
|
+
].select { |p| File.directory?(p) }
|
|
29
|
+
|
|
30
|
+
offenders = []
|
|
31
|
+
roots.each do |root|
|
|
32
|
+
Dir.glob("#{root}/**/*.rb").each do |path|
|
|
33
|
+
content = File.read(path)
|
|
34
|
+
offenders << path if content.match?(/^\s*include\s+ActionController::Live\b/)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if offenders.any?
|
|
39
|
+
warn "\e[31m✗ ActionController::Live found in pgbus web code:\e[0m"
|
|
40
|
+
offenders.each { |p| warn " #{p}" }
|
|
41
|
+
warn ""
|
|
42
|
+
warn " Rationale: the pgbus streams subsystem uses rack.hijack to"
|
|
43
|
+
warn " avoid Puma thread pinning (puma/puma#1009). Including"
|
|
44
|
+
warn " ActionController::Live reintroduces the bug it was designed"
|
|
45
|
+
warn " to avoid. Use Pgbus::Web::StreamApp for SSE endpoints."
|
|
46
|
+
abort
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
puts "\e[32m✓ pgbus web code is free of ActionController::Live\e[0m"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
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.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mikael Henriksson
|
|
@@ -143,6 +143,8 @@ files:
|
|
|
143
143
|
- app/frontend/pgbus/vendor/apexcharts.js
|
|
144
144
|
- app/frontend/pgbus/vendor/turbo.js
|
|
145
145
|
- app/helpers/pgbus/application_helper.rb
|
|
146
|
+
- app/helpers/pgbus/streams_helper.rb
|
|
147
|
+
- app/javascript/pgbus/stream_source_element.js
|
|
146
148
|
- app/models/pgbus/application_record.rb
|
|
147
149
|
- app/models/pgbus/batch_entry.rb
|
|
148
150
|
- app/models/pgbus/blocked_execution.rb
|
|
@@ -155,6 +157,7 @@ files:
|
|
|
155
157
|
- app/models/pgbus/recurring_execution.rb
|
|
156
158
|
- app/models/pgbus/recurring_task.rb
|
|
157
159
|
- app/models/pgbus/semaphore.rb
|
|
160
|
+
- app/models/pgbus/stream_stat.rb
|
|
158
161
|
- app/models/pgbus/uniqueness_key.rb
|
|
159
162
|
- app/views/layouts/pgbus/application.html.erb
|
|
160
163
|
- app/views/pgbus/dashboard/_processes_table.html.erb
|
|
@@ -202,18 +205,24 @@ files:
|
|
|
202
205
|
- lib/generators/pgbus/add_job_locks_generator.rb
|
|
203
206
|
- lib/generators/pgbus/add_job_stats_generator.rb
|
|
204
207
|
- lib/generators/pgbus/add_job_stats_latency_generator.rb
|
|
208
|
+
- lib/generators/pgbus/add_job_stats_queue_index_generator.rb
|
|
205
209
|
- lib/generators/pgbus/add_outbox_generator.rb
|
|
210
|
+
- lib/generators/pgbus/add_presence_generator.rb
|
|
206
211
|
- lib/generators/pgbus/add_queue_states_generator.rb
|
|
207
212
|
- lib/generators/pgbus/add_recurring_generator.rb
|
|
213
|
+
- lib/generators/pgbus/add_stream_stats_generator.rb
|
|
208
214
|
- lib/generators/pgbus/install_generator.rb
|
|
209
215
|
- lib/generators/pgbus/migrate_job_locks_generator.rb
|
|
210
216
|
- lib/generators/pgbus/templates/add_failed_events_unique_index.rb.erb
|
|
211
217
|
- lib/generators/pgbus/templates/add_job_locks.rb.erb
|
|
212
218
|
- lib/generators/pgbus/templates/add_job_stats.rb.erb
|
|
213
219
|
- lib/generators/pgbus/templates/add_job_stats_latency.rb.erb
|
|
220
|
+
- lib/generators/pgbus/templates/add_job_stats_queue_index.rb.erb
|
|
214
221
|
- lib/generators/pgbus/templates/add_outbox.rb.erb
|
|
222
|
+
- lib/generators/pgbus/templates/add_presence.rb.erb
|
|
215
223
|
- lib/generators/pgbus/templates/add_queue_states.rb.erb
|
|
216
224
|
- lib/generators/pgbus/templates/add_recurring_tables.rb.erb
|
|
225
|
+
- lib/generators/pgbus/templates/add_stream_stats.rb.erb
|
|
217
226
|
- lib/generators/pgbus/templates/add_uniqueness_keys.rb.erb
|
|
218
227
|
- lib/generators/pgbus/templates/migrate_job_locks_to_uniqueness_keys.rb.erb
|
|
219
228
|
- lib/generators/pgbus/templates/migration.rb.erb
|
|
@@ -231,6 +240,8 @@ files:
|
|
|
231
240
|
- lib/pgbus/circuit_breaker.rb
|
|
232
241
|
- lib/pgbus/cli.rb
|
|
233
242
|
- lib/pgbus/client.rb
|
|
243
|
+
- lib/pgbus/client/ensure_stream_queue.rb
|
|
244
|
+
- lib/pgbus/client/read_after.rb
|
|
234
245
|
- lib/pgbus/concurrency.rb
|
|
235
246
|
- lib/pgbus/concurrency/blocked_execution.rb
|
|
236
247
|
- lib/pgbus/concurrency/semaphore.rb
|
|
@@ -246,6 +257,8 @@ files:
|
|
|
246
257
|
- lib/pgbus/event_bus/subscriber.rb
|
|
247
258
|
- lib/pgbus/failed_event_recorder.rb
|
|
248
259
|
- lib/pgbus/generators/config_converter.rb
|
|
260
|
+
- lib/pgbus/generators/database_target_detector.rb
|
|
261
|
+
- lib/pgbus/generators/migration_detector.rb
|
|
249
262
|
- lib/pgbus/instrumentation.rb
|
|
250
263
|
- lib/pgbus/outbox.rb
|
|
251
264
|
- lib/pgbus/outbox/poller.rb
|
|
@@ -272,11 +285,30 @@ files:
|
|
|
272
285
|
- lib/pgbus/recurring/task.rb
|
|
273
286
|
- lib/pgbus/serializer.rb
|
|
274
287
|
- lib/pgbus/stat_buffer.rb
|
|
288
|
+
- lib/pgbus/streams.rb
|
|
289
|
+
- lib/pgbus/streams/cursor.rb
|
|
290
|
+
- lib/pgbus/streams/envelope.rb
|
|
291
|
+
- lib/pgbus/streams/filters.rb
|
|
292
|
+
- lib/pgbus/streams/presence.rb
|
|
293
|
+
- lib/pgbus/streams/signed_name.rb
|
|
294
|
+
- lib/pgbus/streams/turbo_broadcastable.rb
|
|
295
|
+
- lib/pgbus/streams/watermark_cache_middleware.rb
|
|
275
296
|
- lib/pgbus/uniqueness.rb
|
|
276
297
|
- lib/pgbus/version.rb
|
|
277
298
|
- lib/pgbus/web/authentication.rb
|
|
278
299
|
- lib/pgbus/web/data_source.rb
|
|
300
|
+
- lib/pgbus/web/stream_app.rb
|
|
301
|
+
- lib/pgbus/web/streamer.rb
|
|
302
|
+
- lib/pgbus/web/streamer/connection.rb
|
|
303
|
+
- lib/pgbus/web/streamer/dispatcher.rb
|
|
304
|
+
- lib/pgbus/web/streamer/heartbeat.rb
|
|
305
|
+
- lib/pgbus/web/streamer/instance.rb
|
|
306
|
+
- lib/pgbus/web/streamer/io_writer.rb
|
|
307
|
+
- lib/pgbus/web/streamer/listener.rb
|
|
308
|
+
- lib/pgbus/web/streamer/registry.rb
|
|
309
|
+
- lib/puma/plugin/pgbus_streams.rb
|
|
279
310
|
- lib/tasks/pgbus_pgmq.rake
|
|
311
|
+
- lib/tasks/pgbus_streams.rake
|
|
280
312
|
homepage: https://github.com/mhenrixon/pgbus
|
|
281
313
|
licenses:
|
|
282
314
|
- MIT
|