pgbus 0.5.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +238 -0
- 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 +118 -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_presence_generator.rb +55 -0
- data/lib/generators/pgbus/add_stream_stats_generator.rb +54 -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/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/capsule_dsl.rb +6 -20
- data/lib/pgbus/configuration.rb +126 -14
- data/lib/pgbus/engine.rb +31 -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 +29 -0
- 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 +29 -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.0
|
|
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
|
|
@@ -203,8 +206,10 @@ files:
|
|
|
203
206
|
- lib/generators/pgbus/add_job_stats_generator.rb
|
|
204
207
|
- lib/generators/pgbus/add_job_stats_latency_generator.rb
|
|
205
208
|
- lib/generators/pgbus/add_outbox_generator.rb
|
|
209
|
+
- lib/generators/pgbus/add_presence_generator.rb
|
|
206
210
|
- lib/generators/pgbus/add_queue_states_generator.rb
|
|
207
211
|
- lib/generators/pgbus/add_recurring_generator.rb
|
|
212
|
+
- lib/generators/pgbus/add_stream_stats_generator.rb
|
|
208
213
|
- lib/generators/pgbus/install_generator.rb
|
|
209
214
|
- lib/generators/pgbus/migrate_job_locks_generator.rb
|
|
210
215
|
- lib/generators/pgbus/templates/add_failed_events_unique_index.rb.erb
|
|
@@ -212,8 +217,10 @@ files:
|
|
|
212
217
|
- lib/generators/pgbus/templates/add_job_stats.rb.erb
|
|
213
218
|
- lib/generators/pgbus/templates/add_job_stats_latency.rb.erb
|
|
214
219
|
- lib/generators/pgbus/templates/add_outbox.rb.erb
|
|
220
|
+
- lib/generators/pgbus/templates/add_presence.rb.erb
|
|
215
221
|
- lib/generators/pgbus/templates/add_queue_states.rb.erb
|
|
216
222
|
- lib/generators/pgbus/templates/add_recurring_tables.rb.erb
|
|
223
|
+
- lib/generators/pgbus/templates/add_stream_stats.rb.erb
|
|
217
224
|
- lib/generators/pgbus/templates/add_uniqueness_keys.rb.erb
|
|
218
225
|
- lib/generators/pgbus/templates/migrate_job_locks_to_uniqueness_keys.rb.erb
|
|
219
226
|
- lib/generators/pgbus/templates/migration.rb.erb
|
|
@@ -231,6 +238,8 @@ files:
|
|
|
231
238
|
- lib/pgbus/circuit_breaker.rb
|
|
232
239
|
- lib/pgbus/cli.rb
|
|
233
240
|
- lib/pgbus/client.rb
|
|
241
|
+
- lib/pgbus/client/ensure_stream_queue.rb
|
|
242
|
+
- lib/pgbus/client/read_after.rb
|
|
234
243
|
- lib/pgbus/concurrency.rb
|
|
235
244
|
- lib/pgbus/concurrency/blocked_execution.rb
|
|
236
245
|
- lib/pgbus/concurrency/semaphore.rb
|
|
@@ -272,11 +281,30 @@ files:
|
|
|
272
281
|
- lib/pgbus/recurring/task.rb
|
|
273
282
|
- lib/pgbus/serializer.rb
|
|
274
283
|
- lib/pgbus/stat_buffer.rb
|
|
284
|
+
- lib/pgbus/streams.rb
|
|
285
|
+
- lib/pgbus/streams/cursor.rb
|
|
286
|
+
- lib/pgbus/streams/envelope.rb
|
|
287
|
+
- lib/pgbus/streams/filters.rb
|
|
288
|
+
- lib/pgbus/streams/presence.rb
|
|
289
|
+
- lib/pgbus/streams/signed_name.rb
|
|
290
|
+
- lib/pgbus/streams/turbo_broadcastable.rb
|
|
291
|
+
- lib/pgbus/streams/watermark_cache_middleware.rb
|
|
275
292
|
- lib/pgbus/uniqueness.rb
|
|
276
293
|
- lib/pgbus/version.rb
|
|
277
294
|
- lib/pgbus/web/authentication.rb
|
|
278
295
|
- lib/pgbus/web/data_source.rb
|
|
296
|
+
- lib/pgbus/web/stream_app.rb
|
|
297
|
+
- lib/pgbus/web/streamer.rb
|
|
298
|
+
- lib/pgbus/web/streamer/connection.rb
|
|
299
|
+
- lib/pgbus/web/streamer/dispatcher.rb
|
|
300
|
+
- lib/pgbus/web/streamer/heartbeat.rb
|
|
301
|
+
- lib/pgbus/web/streamer/instance.rb
|
|
302
|
+
- lib/pgbus/web/streamer/io_writer.rb
|
|
303
|
+
- lib/pgbus/web/streamer/listener.rb
|
|
304
|
+
- lib/pgbus/web/streamer/registry.rb
|
|
305
|
+
- lib/puma/plugin/pgbus_streams.rb
|
|
279
306
|
- lib/tasks/pgbus_pgmq.rake
|
|
307
|
+
- lib/tasks/pgbus_streams.rake
|
|
280
308
|
homepage: https://github.com/mhenrixon/pgbus
|
|
281
309
|
licenses:
|
|
282
310
|
- MIT
|