pgbus 0.22.0 → 0.23.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/README.md +41 -14
  4. data/Rakefile +7 -1
  5. data/app/assets/javascripts/pgbus/stream_source_element.js +17 -3
  6. data/app/assets/javascripts/pgbus/stream_source_element.min.js +4 -4
  7. data/app/assets/javascripts/pgbus/stream_source_element.min.js.map +1 -1
  8. data/app/controllers/pgbus/dead_letter_controller.rb +3 -1
  9. data/app/controllers/pgbus/jobs_controller.rb +2 -1
  10. data/app/models/pgbus/blocked_execution.rb +3 -2
  11. data/app/models/pgbus/queue_state.rb +6 -0
  12. data/app/models/pgbus/uniqueness_key.rb +11 -0
  13. data/config/locales/da.yml +1 -0
  14. data/config/locales/de.yml +1 -0
  15. data/config/locales/en.yml +1 -0
  16. data/config/locales/es.yml +1 -0
  17. data/config/locales/fi.yml +1 -0
  18. data/config/locales/fr.yml +1 -0
  19. data/config/locales/it.yml +1 -0
  20. data/config/locales/ja.yml +1 -0
  21. data/config/locales/nb.yml +1 -0
  22. data/config/locales/nl.yml +1 -0
  23. data/config/locales/pt.yml +1 -0
  24. data/config/locales/sv.yml +1 -0
  25. data/lib/generators/pgbus/fold_queue_name_case_generator.rb +57 -0
  26. data/lib/generators/pgbus/templates/fold_queue_name_case.rb.erb +12 -0
  27. data/lib/generators/pgbus/templates/tune_autovacuum.rb.erb +2 -2
  28. data/lib/generators/pgbus/templates/tune_fillfactor.rb.erb +1 -1
  29. data/lib/pgbus/active_job/adapter.rb +3 -2
  30. data/lib/pgbus/active_job/executor.rb +142 -20
  31. data/lib/pgbus/active_job/quiet_logs.rb +57 -0
  32. data/lib/pgbus/autovacuum_tuning.rb +2 -2
  33. data/lib/pgbus/cli/dlq.rb +2 -1
  34. data/lib/pgbus/client/async_commit.rb +149 -0
  35. data/lib/pgbus/client/native_statements.rb +28 -16
  36. data/lib/pgbus/client.rb +181 -17
  37. data/lib/pgbus/concurrency/blocked_execution.rb +9 -1
  38. data/lib/pgbus/configuration.rb +71 -6
  39. data/lib/pgbus/dead_letter_header.rb +3 -0
  40. data/lib/pgbus/doctor.rb +55 -2
  41. data/lib/pgbus/failed_event_recorder.rb +5 -2
  42. data/lib/pgbus/generators/migration_detector.rb +29 -2
  43. data/lib/pgbus/instrumentation.rb +16 -1
  44. data/lib/pgbus/metrics/subscriber.rb +27 -1
  45. data/lib/pgbus/process/completer.rb +4 -2
  46. data/lib/pgbus/process/worker.rb +28 -3
  47. data/lib/pgbus/queue_name_fold.rb +145 -0
  48. data/lib/pgbus/queue_name_validator.rb +20 -2
  49. data/lib/pgbus/recurring/schedule.rb +22 -13
  50. data/lib/pgbus/stat_buffer.rb +67 -26
  51. data/lib/pgbus/streams/cursor.rb +17 -6
  52. data/lib/pgbus/streams/envelope.rb +16 -0
  53. data/lib/pgbus/streams/key.rb +1 -1
  54. data/lib/pgbus/table_maintenance.rb +1 -1
  55. data/lib/pgbus/uniqueness.rb +43 -16
  56. data/lib/pgbus/version.rb +1 -1
  57. data/lib/pgbus/web/data_source/dead_letter.rb +14 -5
  58. data/lib/pgbus/web/data_source/resend.rb +185 -0
  59. data/lib/pgbus/web/data_source/resend_slot.rb +139 -0
  60. data/lib/pgbus/web/data_source.rb +55 -37
  61. data/lib/pgbus/web/dead_letter_reason.rb +6 -0
  62. data/lib/pgbus/web/streamer/connection.rb +36 -29
  63. data/lib/pgbus/web/streamer/falcon_connection.rb +29 -25
  64. data/lib/pgbus/web/streamer/heartbeat.rb +14 -3
  65. data/lib/pgbus/web/streamer/instance.rb +8 -5
  66. data/lib/pgbus/web/streamer/listener.rb +239 -62
  67. data/lib/pgbus/web/streamer/outbound_pump.rb +6 -4
  68. data/lib/pgbus/web/streamer/registry.rb +55 -29
  69. data/lib/pgbus/web/streamer/stream_event_dispatcher.rb +73 -12
  70. data/lib/tasks/pgbus_queues.rake +27 -0
  71. data/sig/pgbus/active_job/adapter.rbs +1 -1
  72. data/sig/pgbus/active_job/quiet_logs.rbs +11 -0
  73. data/sig/pgbus/client.rbs +6 -5
  74. data/sig/pgbus/configuration.rbs +4 -0
  75. metadata +11 -3
@@ -78,6 +78,7 @@ module Pgbus
78
78
  end
79
79
 
80
80
  DEFAULT_READ_LIMIT = 500
81
+ NO_PAIRS = [].freeze
81
82
 
82
83
  attr_reader :stream_counter
83
84
 
@@ -124,8 +125,10 @@ module Pgbus
124
125
  @fanout_write_deadline_ms = @config.streams_fanout_write_deadline_ms
125
126
  @connect_write_deadline_ms = @config.streams_write_deadline_ms
126
127
  @stream_counter = stream_counter || StreamCounter.new
127
- # stream_name → Array<[connection, Array<Envelope>]>
128
- @in_flight = Hash.new { |h, k| h[k] = [] }
128
+ # stream_name → Array<[connection, Array<Envelope>]>. No default
129
+ # proc: a read for a stream nobody is connecting to (a wake after
130
+ # the last subscriber left) must not leave an entry behind.
131
+ @in_flight = {}
129
132
  # PGMQ full table name (pgbus_<prefix>_<name>) → logical stream
130
133
  # name. Populated on connect so handle_wake can translate
131
134
  # Listener::WakeMessage#queue_name (a full table name, because
@@ -265,7 +268,7 @@ module Pgbus
265
268
  started_at = monotonic_ms
266
269
  stream = @full_to_logical[msg.queue_name] || msg.queue_name
267
270
  registered = @registry.connections_for(stream)
268
- in_flight_pairs = @in_flight[stream]
271
+ in_flight_pairs = @in_flight.fetch(stream, NO_PAIRS)
269
272
  return if registered.empty? && in_flight_pairs.empty?
270
273
 
271
274
  if msg.payload
@@ -285,6 +288,7 @@ module Pgbus
285
288
 
286
289
  envelopes = raw_envelopes.map { |e| unwrap_stream_envelope(e) }
287
290
  max_msg_id = envelopes.map(&:msg_id).max
291
+ frames = frames_for(envelopes) unless registered.empty?
288
292
 
289
293
  registered.each do |conn|
290
294
  visible = visible_envelopes_for(envelopes, conn)
@@ -294,9 +298,9 @@ module Pgbus
294
298
  # Post even when `visible` is empty, with batch max, so an
295
299
  # audience-filtered-away batch still advances the cursor past the
296
300
  # hidden window (issue #321 B2). The pump raises on ephemerals.
297
- @pump.post(conn, visible, max_msg_id, deadline_ms: @fanout_write_deadline_ms)
301
+ @pump.post(conn, visible, max_msg_id, deadline_ms: @fanout_write_deadline_ms, frames: frames)
298
302
  else
299
- safe_enqueue(conn, visible)
303
+ safe_enqueue(conn, visible, frames: frames)
300
304
  advance_scanned_cursor(conn, max_msg_id)
301
305
  end
302
306
  end
@@ -336,8 +340,9 @@ module Pgbus
336
340
  event: normalize_sse_event(parsed["event"])
337
341
  )
338
342
 
343
+ frames = frames_for([envelope]) unless registered.empty?
339
344
  registered.each do |conn|
340
- safe_enqueue(conn, visible_envelopes_for([envelope], conn))
345
+ safe_enqueue(conn, visible_envelopes_for([envelope], conn), frames: frames)
341
346
  end
342
347
  in_flight_pairs.each do |(conn, buffer)|
343
348
  buffer.concat(visible_envelopes_for([envelope], conn))
@@ -367,13 +372,46 @@ module Pgbus
367
372
  # prefix: pgmq.q_<prefixed>.INSERT. Registry and the in-flight
368
373
  # buffer use the logical name. The Dispatcher is the single
369
374
  # translator between the two naming worlds.
375
+ #
376
+ # Only a stream's first subscriber waits on the listener (issue
377
+ # #630). remove_listening is issued in exactly one place,
378
+ # cleanup_stream_if_unused, and only when the registry holds no
379
+ # connection on the stream. So a registered connection, dead or
380
+ # alive, proves the stream's last ensure_listening returned after
381
+ # its last remove_listening was issued. The listener runs commands
382
+ # in order, and a LISTEN that raised is acked only once the reconnect
383
+ # that follows has re-LISTENed it, so the LISTEN is active. Two
384
+ # exceptions. A listener thread on its way out (at stop, or after an
385
+ # unexpected error) releases every waiting caller with nothing
386
+ # LISTENed. And a first connect whose ack timed out (a stuck or
387
+ # reconnecting listener) leaves its LISTEN queued, ahead of any
388
+ # later UNLISTEN, to run when the listener recovers; until then the
389
+ # fast-path connects share the window that first connect already
390
+ # had, and a durable stream's next wake re-reads from the min
391
+ # cursor. A listener reconnect re-LISTENs its whole set; a hub
392
+ # failover replays FailoverListener's subscriptions, which the
393
+ # first-connect / last-disconnect calls keep exact. An empty stream
394
+ # always takes the slow path: that covers a connect that died
395
+ # mid-replay and unlistened without ever registering.
396
+ # @full_to_logical is set here and deleted only by that same
397
+ # cleanup, so it is present whenever the stream is not empty.
398
+ #
399
+ # The fast path holds while the listener reconnects, on purpose.
400
+ # Waiting on a reconnecting listener would cost every connect the
401
+ # full ack budget (health_check_ms + 1 s) for as long as the
402
+ # database stays unreachable: the storm this rule removes. A
403
+ # connect in that window has the same exposure as every connection
404
+ # already registered: a durable stream's next wake after the
405
+ # re-LISTEN re-reads from the min cursor.
370
406
  full_name = notify_queue_name_for(stream)
371
- @full_to_logical[full_name] = stream
372
- @listener.ensure_listening(full_name)
407
+ if @registry.empty?(stream)
408
+ @full_to_logical[full_name] = stream
409
+ @listener.ensure_listening(full_name)
410
+ end
373
411
 
374
412
  # Step 2: install the in-flight buffer BEFORE any read.
375
413
  buffer = []
376
- @in_flight[stream] << [connection, buffer]
414
+ (@in_flight[stream] ||= []) << [connection, buffer]
377
415
 
378
416
  # Step 3: read the archive for anything published before this
379
417
  # connect landed, and write to the connection.
@@ -481,7 +519,7 @@ module Pgbus
481
519
  # 2. @in_flight[stream] (cleared by remove_in_flight already)
482
520
  # 3. Listener's @listening_to set + the PG LISTEN itself
483
521
  def cleanup_stream_if_unused(stream)
484
- return unless @registry.empty?(stream) && @in_flight[stream].empty?
522
+ return unless @registry.empty?(stream) && !@in_flight.key?(stream)
485
523
 
486
524
  full_name = @full_to_logical.key(stream)
487
525
  return unless full_name
@@ -550,11 +588,32 @@ module Pgbus
550
588
  # it implicitly. handle_connect passes @connect_write_deadline_ms
551
589
  # explicitly so a new client's initial replay keeps the full window
552
590
  # (issue #315 item 3).
553
- def safe_enqueue(connection, envelopes_or_buffer, deadline_ms: @fanout_write_deadline_ms)
591
+ #
592
+ # frames: the wake's prebuilt frames (frames_for); nil on the connect
593
+ # replay and the in-flight drain, which frame per connection.
594
+ def safe_enqueue(connection, envelopes_or_buffer, deadline_ms: @fanout_write_deadline_ms, frames: nil)
554
595
  return if connection.dead?
555
596
  return if envelopes_or_buffer.empty?
556
597
 
557
- connection.enqueue(envelopes_or_buffer, deadline_ms: deadline_ms)
598
+ connection.enqueue(envelopes_or_buffer, deadline_ms: deadline_ms, frames: frames)
599
+ end
600
+
601
+ # One SSE frame per envelope per wake, shared by every connection on
602
+ # the stream (issue #621): the bytes depend on the envelope alone, so
603
+ # framing per connection repeated the same work N times. Keyed by the
604
+ # Integer msg_id, never by the envelope (a StreamEnvelope's #hash walks
605
+ # its payload, which would cost what the framing saves); msg_id is
606
+ # unique within a wake. Frozen, values and Hash, so the frames stay
607
+ # Ractor-shareable across the dispatch seam (issue #527).
608
+ def frames_for(envelopes)
609
+ envelopes.to_h do |envelope|
610
+ frame = Pgbus::Streams::Envelope.message(
611
+ id: envelope.msg_id,
612
+ event: Pgbus::Streams::Envelope.sse_event_for(envelope),
613
+ data: envelope.payload
614
+ )
615
+ [envelope.msg_id, frame.freeze]
616
+ end.freeze
558
617
  end
559
618
 
560
619
  def prune_dead(connections)
@@ -565,6 +624,8 @@ module Pgbus
565
624
 
566
625
  def remove_in_flight(stream, connection)
567
626
  pairs = @in_flight[stream]
627
+ return unless pairs
628
+
568
629
  pairs.reject! { |(conn, _buf)| conn.equal?(connection) }
569
630
  @in_flight.delete(stream) if pairs.empty?
570
631
  end
@@ -9,6 +9,33 @@ namespace :pgbus do
9
9
  puts "Done. FIFO indexes created on all queues."
10
10
  end
11
11
 
12
+ # Issue #633: the pgbus:fold_queue_name_case migration runs once; a
13
+ # mixed-case pgmq.meta row an older process recreated after it is folded
14
+ # here (pgbus doctor's "Queue name case" check names them).
15
+ desc "Spell mixed-case queues (pgmq.meta, NOTIFY triggers, pgbus's queue-name columns) in lower case"
16
+ task fold_case: :environment do
17
+ # The fold writes pgmq.meta and pgbus's tables through one connection,
18
+ # the one pgbus's models (and its migrations) use; a database without
19
+ # pgmq.meta there (PGMQ reached through database_url elsewhere) is
20
+ # refused rather than half-folded.
21
+ pool = Pgbus.configuration.connects_to ? Pgbus::BusRecord.connection_pool : ActiveRecord::Base.connection_pool
22
+ names = pool.with_connection do |connection|
23
+ unless connection.select_value("SELECT to_regclass('pgmq.meta')")
24
+ abort "pgmq.meta is not in the database pgbus's models use (#{connection.current_database}); " \
25
+ "run the fold where pgbus's tables and PGMQ live together"
26
+ end
27
+
28
+ prefix = "#{Pgbus.configuration.queue_prefix.to_s.downcase}_"
29
+ found = connection.select_values(
30
+ "SELECT queue_name FROM pgmq.meta WHERE queue_name <> lower(queue_name) " \
31
+ "AND left(lower(queue_name), length(#{connection.quote(prefix)})) = #{connection.quote(prefix)} ORDER BY queue_name"
32
+ )
33
+ connection.transaction { Pgbus::QueueNameFold.run!(connection) }
34
+ found
35
+ end
36
+ puts names.empty? ? "Every queue is already spelled in lower case." : "Folded: #{names.join(", ")}"
37
+ end
38
+
12
39
  desc "Create FIFO index on a specific queue (QUEUE=name)"
13
40
  task fifo_index: :environment do
14
41
  queue = ENV.fetch("QUEUE") do
@@ -19,7 +19,7 @@ module Pgbus
19
19
  module Uniqueness
20
20
  module ClassMethods
21
21
  # Any other keyword raises ArgumentError (lock_ttl: with a pointer to 1.0's removal).
22
- def ensures_uniqueness: (?strategy: :until_executed | :while_executing, ?key: untyped,
22
+ def ensures_uniqueness: (?strategy: :until_executed | :until_executing | :while_executing, ?key: untyped,
23
23
  ?on_conflict: :reject | :discard | :log) -> untyped
24
24
  def pgbus_uniqueness: () -> Hash[Symbol, untyped]?
25
25
  end
@@ -0,0 +1,11 @@
1
+ module Pgbus
2
+ module ActiveJob
3
+ # config.quiet_active_job_logs: a worker process unsubscribes
4
+ # ActiveJob::LogSubscriber from perform_start and perform.
5
+ module QuietLogs
6
+ EVENTS: Array[String]
7
+
8
+ def self.apply!: (?notifier: untyped) -> bool
9
+ end
10
+ end
11
+ end
data/sig/pgbus/client.rbs CHANGED
@@ -3,8 +3,8 @@
3
3
  # public method is missing here.
4
4
  module Pgbus
5
5
  class Client
6
- def archive_batch: (untyped queue_name, untyped msg_ids, ?prefixed: untyped) -> untyped
7
- def archive_message: (untyped queue_name, untyped msg_id, ?prefixed: untyped) -> untyped
6
+ def archive_batch: (untyped queue_name, untyped msg_ids, ?prefixed: untyped, ?job_completion: bool) -> untyped
7
+ def archive_message: (untyped queue_name, untyped msg_id, ?prefixed: untyped, ?job_completion: bool) -> untyped
8
8
  def bind_topic: (untyped pattern, untyped queue_name) -> untyped
9
9
  def close: () -> untyped
10
10
  def config: () -> untyped
@@ -14,9 +14,9 @@ module Pgbus
14
14
  def create_fifo_index: (untyped queue_name) -> untyped
15
15
  def create_fifo_indexes_all: () -> untyped
16
16
  def dead_letter_physical_name: (untyped queue_name, ?prefixed: untyped) -> untyped
17
- def delete_batch: (untyped queue_name, untyped msg_ids, ?prefixed: untyped) -> untyped
18
- def delete_message: (untyped queue_name, untyped msg_id, ?prefixed: untyped) -> untyped
19
- def drop_queue: (untyped queue_name, ?prefixed: untyped) -> untyped
17
+ def delete_batch: (untyped queue_name, untyped msg_ids, ?prefixed: untyped, ?job_completion: bool) -> untyped
18
+ def delete_message: (untyped queue_name, untyped msg_id, ?prefixed: untyped, ?job_completion: bool) -> untyped
19
+ def drop_queue: (untyped queue_name, ?prefixed: untyped) ?{ () -> untyped } -> untyped
20
20
  def ensure_all_queues: () -> untyped
21
21
  def ensure_dead_letter_queue: (untyped name) -> untyped
22
22
  def ensure_fair_index: (untyped queue_name) -> untyped
@@ -32,6 +32,7 @@ module Pgbus
32
32
  def message_in_queue?: (untyped queue_name, msg_id: untyped, ?prefixed: untyped) -> bool?
33
33
  def message_with_job_id?: (untyped queue_name, job_id: untyped, ?prefixed: untyped) -> bool?
34
34
  def metrics: (?untyped queue_name) -> untyped
35
+ def mixed_case_queue_names: () -> Array[String]
35
36
  def move_to_dead_letter: (untyped queue_name, untyped message, ?headers: untyped) -> untyped
36
37
  def native_ready?: (String full_name) -> bool
37
38
  def notify_enabled?: (untyped queue_name) -> bool
@@ -36,6 +36,8 @@ module Pgbus
36
36
  def completion_batch_size=: (untyped) -> untyped
37
37
  def completion_batching: () -> bool
38
38
  def completion_batching=: (untyped) -> untyped
39
+ def completion_synchronous_commit: () -> bool
40
+ def completion_synchronous_commit=: (bool value) -> bool
39
41
  def connection_guc_mode: () -> Symbol
40
42
  def connection_guc_mode=: (untyped mode) -> untyped
41
43
  def connection_options: () -> untyped
@@ -152,6 +154,8 @@ module Pgbus
152
154
  def queue_name: (untyped name) -> untyped
153
155
  def queue_prefix: () -> String
154
156
  def queue_prefix=: (untyped) -> untyped
157
+ def quiet_active_job_logs: () -> bool
158
+ def quiet_active_job_logs=: (bool value) -> bool
155
159
  def read_ahead: () -> Integer
156
160
  def read_ahead=: (untyped value) -> untyped
157
161
  def read_ahead_for: (untyped entry) -> untyped
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.22.0
4
+ version: 0.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
@@ -63,14 +63,14 @@ dependencies:
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: 0.7.1
66
+ version: 0.8.2
67
67
  type: :runtime
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: 0.7.1
73
+ version: 0.8.2
74
74
  - !ruby/object:Gem::Dependency
75
75
  name: railties
76
76
  requirement: !ruby/object:Gem::Requirement
@@ -302,6 +302,7 @@ files:
302
302
  - lib/generators/pgbus/add_uniqueness_keys_generator.rb
303
303
  - lib/generators/pgbus/add_workflow_signals_generator.rb
304
304
  - lib/generators/pgbus/add_workflows_generator.rb
305
+ - lib/generators/pgbus/fold_queue_name_case_generator.rb
305
306
  - lib/generators/pgbus/install_generator.rb
306
307
  - lib/generators/pgbus/migrate_job_locks_generator.rb
307
308
  - lib/generators/pgbus/migration_path.rb
@@ -325,6 +326,7 @@ files:
325
326
  - lib/generators/pgbus/templates/add_workflow_signals.rb.erb
326
327
  - lib/generators/pgbus/templates/add_workflows.rb.erb
327
328
  - lib/generators/pgbus/templates/deploy_tasks.yml.erb
329
+ - lib/generators/pgbus/templates/fold_queue_name_case.rb.erb
328
330
  - lib/generators/pgbus/templates/initializer.rb.erb
329
331
  - lib/generators/pgbus/templates/migrate_job_locks_to_uniqueness_keys.rb.erb
330
332
  - lib/generators/pgbus/templates/migration.rb.erb
@@ -343,6 +345,7 @@ files:
343
345
  - lib/pgbus/active_job/current_attributes.rb
344
346
  - lib/pgbus/active_job/delivery.rb
345
347
  - lib/pgbus/active_job/executor.rb
348
+ - lib/pgbus/active_job/quiet_logs.rb
346
349
  - lib/pgbus/autovacuum_tuning.rb
347
350
  - lib/pgbus/batch.rb
348
351
  - lib/pgbus/batch/builder.rb
@@ -353,6 +356,7 @@ files:
353
356
  - lib/pgbus/cli/dashboard.rb
354
357
  - lib/pgbus/cli/dlq.rb
355
358
  - lib/pgbus/client.rb
359
+ - lib/pgbus/client/async_commit.rb
356
360
  - lib/pgbus/client/connection_health.rb
357
361
  - lib/pgbus/client/ensure_stream_queue.rb
358
362
  - lib/pgbus/client/fair_read.rb
@@ -484,6 +488,7 @@ files:
484
488
  - lib/pgbus/process/wildcard_queue_resolver.rb
485
489
  - lib/pgbus/process/worker.rb
486
490
  - lib/pgbus/queue_factory.rb
491
+ - lib/pgbus/queue_name_fold.rb
487
492
  - lib/pgbus/queue_name_validator.rb
488
493
  - lib/pgbus/rate_counter.rb
489
494
  - lib/pgbus/recurring/already_recorded.rb
@@ -534,6 +539,8 @@ files:
534
539
  - lib/pgbus/web/data_source/list_counts.rb
535
540
  - lib/pgbus/web/data_source/process_list.rb
536
541
  - lib/pgbus/web/data_source/queue_summary.rb
542
+ - lib/pgbus/web/data_source/resend.rb
543
+ - lib/pgbus/web/data_source/resend_slot.rb
537
544
  - lib/pgbus/web/data_source/workflow_actions.rb
538
545
  - lib/pgbus/web/data_source/workflow_insights.rb
539
546
  - lib/pgbus/web/data_source/workflow_list.rb
@@ -615,6 +622,7 @@ files:
615
622
  - lib/tasks/pgbus_streams.rake
616
623
  - sig/pgbus.rbs
617
624
  - sig/pgbus/active_job/adapter.rbs
625
+ - sig/pgbus/active_job/quiet_logs.rbs
618
626
  - sig/pgbus/client.rbs
619
627
  - sig/pgbus/configuration.rbs
620
628
  - sig/pgbus/configuration/snapshot.rbs