pgbus 0.6.6 → 0.6.8

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.
@@ -10,6 +10,28 @@ it:
10
10
  pid: PID
11
11
  status: Stato
12
12
  title: Processi attivi
13
+ queue_health:
14
+ dead_tuples: Tuple morte
15
+ headers:
16
+ bloat: Bloat
17
+ dead: Morte
18
+ kind: Tipo
19
+ last_vacuum: Ultimo Vacuum
20
+ live: Attive
21
+ table: Tabella
22
+ kinds:
23
+ archive: Archivio
24
+ queue: Coda
25
+ last_vacuum: Ultimo Vacuum
26
+ live: Attive
27
+ mvcc_horizon: Orizzonte MVCC
28
+ oldest_open_txn: Transazione aperta più vecchia
29
+ oldest_vacuum_ago: Vacuum tabella più vecchio
30
+ tables_need_vacuum:
31
+ one: "%{count} tabella necessita di vacuum"
32
+ other: "%{count} tabelle necessitano di vacuum"
33
+ title: Salute delle Code
34
+ worst_bloat: Peggior Bloat
13
35
  queues_table:
14
36
  empty: Nessuna coda trovata
15
37
  headers:
@@ -337,6 +359,15 @@ it:
337
359
  resume: Riprendi
338
360
  retry: Riprova
339
361
  retry_confirm: Reimpostare il timeout di visibilità e riprovare?
362
+ table_health:
363
+ headers:
364
+ bloat: Bloat
365
+ dead: Morte
366
+ last_vacuum: Ultimo Vacuum
367
+ live: Attive
368
+ table: Tabella
369
+ oldest_txn: 'Transazione aperta più vecchia:'
370
+ title: Salute delle Tabelle
340
371
  total: 'Totale:'
341
372
  visible: 'Visibile:'
342
373
  recurring_tasks:
@@ -345,10 +376,6 @@ it:
345
376
  one: "%{count} attività configurata"
346
377
  other: "%{count} attività configurate"
347
378
  title: Attività ricorrenti
348
- toggle:
349
- disabled: Attività disabilitata
350
- enabled: Attività abilitata
351
- failed: Impossibile cambiare lo stato dell'attività
352
379
  show:
353
380
  back: Indietro
354
381
  configuration: Configurazione
@@ -392,3 +419,7 @@ it:
392
419
  task: Attività
393
420
  never: Mai
394
421
  run_now: Esegui ora
422
+ toggle:
423
+ disabled: Attività disabilitata
424
+ enabled: Attività abilitata
425
+ failed: Impossibile cambiare lo stato dell'attività
@@ -10,6 +10,28 @@ ja:
10
10
  pid: PID
11
11
  status: ステータス
12
12
  title: アクティブなプロセス
13
+ queue_health:
14
+ dead_tuples: デッドタプル
15
+ headers:
16
+ bloat: Bloat
17
+ dead: デッド
18
+ kind: 種類
19
+ last_vacuum: 最終Vacuum
20
+ live: ライブ
21
+ table: テーブル
22
+ kinds:
23
+ archive: アーカイブ
24
+ queue: キュー
25
+ last_vacuum: 最終Vacuum
26
+ live: ライブ
27
+ mvcc_horizon: MVCCホライズン
28
+ oldest_open_txn: 最も古い未完了トランザクション
29
+ oldest_vacuum_ago: 最も古いテーブルvacuum
30
+ tables_need_vacuum:
31
+ one: "%{count} テーブルがvacuumを必要としています"
32
+ other: "%{count} テーブルがvacuumを必要としています"
33
+ title: キューの健全性
34
+ worst_bloat: 最悪のBloat
13
35
  queues_table:
14
36
  empty: キューが見つかりません
15
37
  headers:
@@ -337,6 +359,15 @@ ja:
337
359
  resume: 再開
338
360
  retry: リトライ
339
361
  retry_confirm: 可視性タイムアウトをリセットしてリトライしますか?
362
+ table_health:
363
+ headers:
364
+ bloat: Bloat
365
+ dead: デッド
366
+ last_vacuum: 最終Vacuum
367
+ live: ライブ
368
+ table: テーブル
369
+ oldest_txn: '最も古い未完了トランザクション:'
370
+ title: テーブルの健全性
340
371
  total: 合計:
341
372
  visible: 表示中:
342
373
  recurring_tasks:
@@ -345,10 +376,6 @@ ja:
345
376
  one: "%{count} タスクが設定されています"
346
377
  other: "%{count} タスクが設定されています"
347
378
  title: 定期タスク
348
- toggle:
349
- disabled: タスクが無効になりました
350
- enabled: タスクが有効になりました
351
- failed: タスクの切り替えに失敗しました
352
379
  show:
353
380
  back: 戻る
354
381
  configuration: 設定
@@ -392,3 +419,7 @@ ja:
392
419
  task: タスク
393
420
  never: なし
394
421
  run_now: 今すぐ実行
422
+ toggle:
423
+ disabled: タスクが無効になりました
424
+ enabled: タスクが有効になりました
425
+ failed: タスクの切り替えに失敗しました
@@ -10,6 +10,28 @@ nb:
10
10
  pid: PID
11
11
  status: Status
12
12
  title: Aktive prosesser
13
+ queue_health:
14
+ dead_tuples: Døde tupler
15
+ headers:
16
+ bloat: Bloat
17
+ dead: Døde
18
+ kind: Type
19
+ last_vacuum: Siste Vacuum
20
+ live: Levende
21
+ table: Tabell
22
+ kinds:
23
+ archive: Arkiv
24
+ queue: Kø
25
+ last_vacuum: Siste Vacuum
26
+ live: Levende
27
+ mvcc_horizon: MVCC-horisont
28
+ oldest_open_txn: Eldste åpne transaksjon
29
+ oldest_vacuum_ago: Eldste tabell-vacuum
30
+ tables_need_vacuum:
31
+ one: "%{count} tabell trenger vacuum"
32
+ other: "%{count} tabeller trenger vacuum"
33
+ title: Køhelse
34
+ worst_bloat: Verste Bloat
13
35
  queues_table:
14
36
  empty: Ingen køer funnet
15
37
  headers:
@@ -337,6 +359,15 @@ nb:
337
359
  resume: Gjenoppta
338
360
  retry: Prøv igjen
339
361
  retry_confirm: Tilbakestill synlighetstidsavbrudd og prøv igjen?
362
+ table_health:
363
+ headers:
364
+ bloat: Bloat
365
+ dead: Døde
366
+ last_vacuum: Siste Vacuum
367
+ live: Levende
368
+ table: Tabell
369
+ oldest_txn: 'Eldste åpne transaksjon:'
370
+ title: Tabellhelse
340
371
  total: 'Totalt:'
341
372
  visible: 'Synlig:'
342
373
  recurring_tasks:
@@ -345,10 +376,6 @@ nb:
345
376
  one: "%{count} oppgave konfigurert"
346
377
  other: "%{count} oppgaver konfigurert"
347
378
  title: Gjentakende oppgaver
348
- toggle:
349
- disabled: Oppgave deaktivert
350
- enabled: Oppgave aktivert
351
- failed: Kunne ikke endre oppgave
352
379
  show:
353
380
  back: Tilbake
354
381
  configuration: Konfigurasjon
@@ -392,3 +419,7 @@ nb:
392
419
  task: Oppgave
393
420
  never: Aldri
394
421
  run_now: Kjør nå
422
+ toggle:
423
+ disabled: Oppgave deaktivert
424
+ enabled: Oppgave aktivert
425
+ failed: Kunne ikke endre oppgave
@@ -10,6 +10,28 @@ nl:
10
10
  pid: PID
11
11
  status: Status
12
12
  title: Actieve processen
13
+ queue_health:
14
+ dead_tuples: Dode tupels
15
+ headers:
16
+ bloat: Bloat
17
+ dead: Dood
18
+ kind: Type
19
+ last_vacuum: Laatste Vacuum
20
+ live: Actief
21
+ table: Tabel
22
+ kinds:
23
+ archive: Archief
24
+ queue: Wachtrij
25
+ last_vacuum: Laatste Vacuum
26
+ live: Actief
27
+ mvcc_horizon: MVCC-horizon
28
+ oldest_open_txn: Oudste open transactie
29
+ oldest_vacuum_ago: Oudste tabel-vacuum
30
+ tables_need_vacuum:
31
+ one: "%{count} tabel heeft vacuum nodig"
32
+ other: "%{count} tabellen hebben vacuum nodig"
33
+ title: Wachtrijgezondheid
34
+ worst_bloat: Ergste Bloat
13
35
  queues_table:
14
36
  empty: Geen wachtrijen gevonden
15
37
  headers:
@@ -337,6 +359,15 @@ nl:
337
359
  resume: Hervatten
338
360
  retry: Opnieuw proberen
339
361
  retry_confirm: Zichtbaarheidstimeout resetten en opnieuw proberen?
362
+ table_health:
363
+ headers:
364
+ bloat: Bloat
365
+ dead: Dood
366
+ last_vacuum: Laatste Vacuum
367
+ live: Actief
368
+ table: Tabel
369
+ oldest_txn: 'Oudste open transactie:'
370
+ title: Tabelgezondheid
340
371
  total: 'Totaal:'
341
372
  visible: 'Zichtbaar:'
342
373
  recurring_tasks:
@@ -345,10 +376,6 @@ nl:
345
376
  one: "%{count} taak geconfigureerd"
346
377
  other: "%{count} taken geconfigureerd"
347
378
  title: Terugkerende taken
348
- toggle:
349
- disabled: Taak uitgeschakeld
350
- enabled: Taak ingeschakeld
351
- failed: Kon taak niet omschakelen
352
379
  show:
353
380
  back: Terug
354
381
  configuration: Configuratie
@@ -392,3 +419,7 @@ nl:
392
419
  task: Taak
393
420
  never: Nooit
394
421
  run_now: Nu uitvoeren
422
+ toggle:
423
+ disabled: Taak uitgeschakeld
424
+ enabled: Taak ingeschakeld
425
+ failed: Kon taak niet omschakelen
@@ -10,6 +10,28 @@ pt:
10
10
  pid: PID
11
11
  status: Status
12
12
  title: Processos Ativos
13
+ queue_health:
14
+ dead_tuples: Tuplas mortas
15
+ headers:
16
+ bloat: Bloat
17
+ dead: Mortas
18
+ kind: Tipo
19
+ last_vacuum: Último Vacuum
20
+ live: Ativas
21
+ table: Tabela
22
+ kinds:
23
+ archive: Arquivo
24
+ queue: Fila
25
+ last_vacuum: Último Vacuum
26
+ live: Ativas
27
+ mvcc_horizon: Horizonte MVCC
28
+ oldest_open_txn: Transação aberta mais antiga
29
+ oldest_vacuum_ago: Vacuum de tabela mais antigo
30
+ tables_need_vacuum:
31
+ one: "%{count} tabela precisa de vacuum"
32
+ other: "%{count} tabelas precisam de vacuum"
33
+ title: Saúde das Filas
34
+ worst_bloat: Pior Bloat
13
35
  queues_table:
14
36
  empty: Nenhuma fila encontrada
15
37
  headers:
@@ -337,6 +359,15 @@ pt:
337
359
  resume: Retomar
338
360
  retry: Tentar novamente
339
361
  retry_confirm: Redefinir tempo de visibilidade e tentar novamente?
362
+ table_health:
363
+ headers:
364
+ bloat: Bloat
365
+ dead: Mortas
366
+ last_vacuum: Último Vacuum
367
+ live: Ativas
368
+ table: Tabela
369
+ oldest_txn: 'Transação aberta mais antiga:'
370
+ title: Saúde das Tabelas
340
371
  total: 'Total:'
341
372
  visible: 'Visível:'
342
373
  recurring_tasks:
@@ -345,10 +376,6 @@ pt:
345
376
  one: "%{count} tarefa configurada"
346
377
  other: "%{count} tarefas configuradas"
347
378
  title: Tarefas Recorrentes
348
- toggle:
349
- disabled: Tarefa desativada
350
- enabled: Tarefa ativada
351
- failed: Falha ao alternar tarefa
352
379
  show:
353
380
  back: Voltar
354
381
  configuration: Configuração
@@ -392,3 +419,7 @@ pt:
392
419
  task: Tarefa
393
420
  never: Nunca
394
421
  run_now: Executar Agora
422
+ toggle:
423
+ disabled: Tarefa desativada
424
+ enabled: Tarefa ativada
425
+ failed: Falha ao alternar tarefa
@@ -10,6 +10,28 @@ sv:
10
10
  pid: PID
11
11
  status: Status
12
12
  title: Aktiva processer
13
+ queue_health:
14
+ dead_tuples: Döda tuplar
15
+ headers:
16
+ bloat: Bloat
17
+ dead: Döda
18
+ kind: Typ
19
+ last_vacuum: Senaste Vacuum
20
+ live: Levande
21
+ table: Tabell
22
+ kinds:
23
+ archive: Arkiv
24
+ queue: Kö
25
+ last_vacuum: Senaste Vacuum
26
+ live: Levande
27
+ mvcc_horizon: MVCC-horisont
28
+ oldest_open_txn: Äldsta öppna transaktion
29
+ oldest_vacuum_ago: Äldsta tabell-vacuum
30
+ tables_need_vacuum:
31
+ one: "%{count} tabell behöver vacuum"
32
+ other: "%{count} tabeller behöver vacuum"
33
+ title: Köhälsa
34
+ worst_bloat: Värsta Bloat
13
35
  queues_table:
14
36
  empty: Inga köer hittades
15
37
  headers:
@@ -337,6 +359,15 @@ sv:
337
359
  resume: Återuppta
338
360
  retry: Försök igen
339
361
  retry_confirm: Återställ synlighetstimeout och försök igen?
362
+ table_health:
363
+ headers:
364
+ bloat: Bloat
365
+ dead: Döda
366
+ last_vacuum: Senaste Vacuum
367
+ live: Levande
368
+ table: Tabell
369
+ oldest_txn: 'Äldsta öppna transaktion:'
370
+ title: Tabellhälsa
340
371
  total: 'Totalt:'
341
372
  visible: 'Synliga:'
342
373
  recurring_tasks:
@@ -345,10 +376,6 @@ sv:
345
376
  one: "%{count} uppgift konfigurerad"
346
377
  other: "%{count} uppgifter konfigurerade"
347
378
  title: Återkommande uppgifter
348
- toggle:
349
- disabled: Uppgift inaktiverad
350
- enabled: Uppgift aktiverad
351
- failed: Kunde inte ändra uppgift
352
379
  show:
353
380
  back: Tillbaka
354
381
  configuration: Konfiguration
@@ -392,3 +419,7 @@ sv:
392
419
  task: Uppgift
393
420
  never: Aldrig
394
421
  run_now: Kör nu
422
+ toggle:
423
+ disabled: Uppgift inaktiverad
424
+ enabled: Uppgift aktiverad
425
+ failed: Kunde inte ändra uppgift
@@ -150,6 +150,12 @@ class CreatePgbusTables < ActiveRecord::Migration<%= migration_version %>
150
150
  # Create default queues via PGMQ
151
151
  execute "SELECT pgmq.create('pgbus_default')"
152
152
  execute "SELECT pgmq.create('pgbus_default_dlq')"
153
+
154
+ # Tune autovacuum for queue/archive tables and high-churn pgbus tables.
155
+ # Default settings are too conservative for the insert/delete churn of
156
+ # queue processing and concurrency lock management.
157
+ execute Pgbus::AutovacuumTuning.sql_for_all_queues
158
+ execute Pgbus::AutovacuumTuning.sql_for_high_churn_tables
153
159
  end
154
160
 
155
161
  def down
@@ -0,0 +1,38 @@
1
+ class TunePgbusAutovacuum < ActiveRecord::Migration<%= migration_version %>
2
+ def up
3
+ # Apply aggressive autovacuum settings to all existing PGMQ queue and
4
+ # archive tables. Queue tables have very high insert/delete churn from
5
+ # the read→process→archive cycle; default autovacuum settings (vacuum
6
+ # at 20% dead tuples) allow dead tuple accumulation that bloats indexes
7
+ # and degrades lock acquisition times.
8
+ #
9
+ # New queues created after this migration automatically receive these
10
+ # settings via Pgbus::Client at queue creation time.
11
+ execute Pgbus::AutovacuumTuning.sql_for_all_queues
12
+
13
+ # Also tune pgbus-owned tables with high write churn:
14
+ # - pgbus_semaphores: rapid upsert+increment per job, periodic expiry
15
+ # - pgbus_uniqueness_keys: INSERT on enqueue, DELETE on completion
16
+ # - pgbus_processed_events: INSERT per event, bulk DELETE on TTL expiry
17
+ execute Pgbus::AutovacuumTuning.sql_for_high_churn_tables
18
+ end
19
+
20
+ def down
21
+ # Reset to PostgreSQL defaults
22
+ execute <<~SQL
23
+ DO $$
24
+ DECLARE
25
+ q RECORD;
26
+ BEGIN
27
+ FOR q IN SELECT queue_name FROM pgmq.meta LOOP
28
+ EXECUTE format('ALTER TABLE pgmq.q_%I RESET (autovacuum_vacuum_scale_factor, autovacuum_vacuum_cost_delay, autovacuum_analyze_scale_factor)', q.queue_name);
29
+ EXECUTE format('ALTER TABLE pgmq.a_%I RESET (autovacuum_vacuum_scale_factor, autovacuum_vacuum_cost_delay, autovacuum_analyze_scale_factor)', q.queue_name);
30
+ END LOOP;
31
+ END $$;
32
+ SQL
33
+
34
+ Pgbus::AutovacuumTuning::HIGH_CHURN_TABLES.each do |table|
35
+ execute "ALTER TABLE #{table} RESET (autovacuum_vacuum_scale_factor, autovacuum_vacuum_cost_delay, autovacuum_analyze_scale_factor)"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module Pgbus
7
+ module Generators
8
+ class TuneAutovacuumGenerator < Rails::Generators::Base
9
+ include ActiveRecord::Generators::Migration
10
+
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ desc "Tune autovacuum settings on PGMQ queue and archive tables for optimal queue health"
14
+
15
+ class_option :database,
16
+ type: :string,
17
+ default: nil,
18
+ desc: "Use a separate database for pgbus tables (e.g. --database=pgbus)"
19
+
20
+ def create_migration_file
21
+ if separate_database?
22
+ migration_template "tune_autovacuum.rb.erb",
23
+ "db/pgbus_migrate/tune_pgbus_autovacuum.rb"
24
+ else
25
+ migration_template "tune_autovacuum.rb.erb",
26
+ "db/migrate/tune_pgbus_autovacuum.rb"
27
+ end
28
+ end
29
+
30
+ def display_post_install
31
+ say ""
32
+ say "Pgbus autovacuum tuning migration created!", :green
33
+ say ""
34
+ say "This migration applies aggressive autovacuum settings to all existing"
35
+ say "PGMQ queue and archive tables. New queues created at runtime will"
36
+ say "automatically receive these settings."
37
+ say ""
38
+ say "Next steps:"
39
+ say " 1. Run: rails db:migrate#{":#{options[:database]}" if separate_database?}"
40
+ say " 2. Restart pgbus: bin/pgbus start"
41
+ say ""
42
+ end
43
+
44
+ private
45
+
46
+ def migration_version
47
+ "[#{ActiveRecord::Migration.current_version}]"
48
+ end
49
+
50
+ def separate_database?
51
+ options[:database].present?
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pgbus
4
+ # Shared autovacuum storage parameters for tables with high write churn.
5
+ #
6
+ # Queue tables (q_*) have high insert/delete churn: every read + archive
7
+ # cycle deletes from q_ and inserts into a_. Default autovacuum settings
8
+ # (vacuum at 20% dead tuples) are far too conservative — dead tuples
9
+ # accumulate, bloat B-tree indexes, and eventually degrade lock acquisition
10
+ # times. See: https://planetscale.com/blog/keeping-a-postgres-queue-healthy
11
+ #
12
+ # Several pgbus-owned tables share similar churn patterns:
13
+ # - pgbus_semaphores: rapid upsert+increment per job, periodic expiry
14
+ # - pgbus_uniqueness_keys: INSERT on enqueue, DELETE on completion
15
+ # - pgbus_processed_events: INSERT per event, bulk DELETE on TTL expiry
16
+ #
17
+ # Used by:
18
+ # - Client#ensure_single_queue (runtime, on queue creation)
19
+ # - CreatePgbusTables migration (fresh install)
20
+ # - TunePgbusAutovacuum migration (upgrade for existing installations)
21
+ module AutovacuumTuning
22
+ # Queue tables: very aggressive — high delete rate from read+archive.
23
+ QUEUE_SETTINGS = {
24
+ "autovacuum_vacuum_scale_factor" => "0.01",
25
+ "autovacuum_vacuum_cost_delay" => "2",
26
+ "autovacuum_analyze_scale_factor" => "0.05"
27
+ }.freeze
28
+
29
+ # Archive tables: moderately aggressive — append-heavy with periodic purge.
30
+ ARCHIVE_SETTINGS = {
31
+ "autovacuum_vacuum_scale_factor" => "0.05",
32
+ "autovacuum_vacuum_cost_delay" => "5",
33
+ "autovacuum_analyze_scale_factor" => "0.05"
34
+ }.freeze
35
+
36
+ # High-churn pgbus tables: rapid INSERT/DELETE or upsert cycles.
37
+ # - semaphores: upsert + increment per job acquire, decrement on release, periodic expiry
38
+ # - uniqueness_keys: INSERT on enqueue, DELETE on job completion (fast lifecycle)
39
+ # - processed_events: INSERT per event handler, bulk DELETE on idempotency TTL expiry
40
+ HIGH_CHURN_SETTINGS = {
41
+ "autovacuum_vacuum_scale_factor" => "0.02",
42
+ "autovacuum_vacuum_cost_delay" => "2",
43
+ "autovacuum_analyze_scale_factor" => "0.05"
44
+ }.freeze
45
+
46
+ HIGH_CHURN_TABLES = %w[
47
+ pgbus_semaphores
48
+ pgbus_uniqueness_keys
49
+ pgbus_processed_events
50
+ ].freeze
51
+
52
+ class << self
53
+ # Generate ALTER TABLE SQL for a single queue's tables.
54
+ def sql_for_queue(queue_name)
55
+ [
56
+ alter_table_sql("pgmq.q_#{queue_name}", QUEUE_SETTINGS),
57
+ alter_table_sql("pgmq.a_#{queue_name}", ARCHIVE_SETTINGS)
58
+ ].join("\n")
59
+ end
60
+
61
+ # Generate ALTER TABLE SQL for all queues discovered via pgmq.meta.
62
+ def sql_for_all_queues
63
+ <<~SQL
64
+ DO $$
65
+ DECLARE
66
+ q RECORD;
67
+ BEGIN
68
+ FOR q IN SELECT queue_name FROM pgmq.meta LOOP
69
+ EXECUTE format('ALTER TABLE pgmq.q_%I SET (#{settings_clause(QUEUE_SETTINGS)})', q.queue_name);
70
+ EXECUTE format('ALTER TABLE pgmq.a_%I SET (#{settings_clause(ARCHIVE_SETTINGS)})', q.queue_name);
71
+ END LOOP;
72
+ END $$;
73
+ SQL
74
+ end
75
+
76
+ # Generate ALTER TABLE SQL for pgbus-owned high-churn tables.
77
+ def sql_for_high_churn_tables
78
+ HIGH_CHURN_TABLES.map { |table| alter_table_sql(table, HIGH_CHURN_SETTINGS, if_exists: true) }.join("\n")
79
+ end
80
+
81
+ private
82
+
83
+ def alter_table_sql(table, settings, if_exists: false)
84
+ prefix = if_exists ? "ALTER TABLE IF EXISTS" : "ALTER TABLE"
85
+ "#{prefix} #{table} SET (#{settings_clause(settings)});"
86
+ end
87
+
88
+ def settings_clause(settings)
89
+ settings.map { |k, v| "#{k} = #{v}" }.join(", ")
90
+ end
91
+ end
92
+ end
93
+ end
data/lib/pgbus/client.rb CHANGED
@@ -75,7 +75,10 @@ module Pgbus
75
75
  return if @queues_created[dlq_name]
76
76
 
77
77
  @queues_created.compute_if_absent(dlq_name) do
78
- synchronized { @pgmq.create(dlq_name) }
78
+ synchronized do
79
+ @pgmq.create(dlq_name)
80
+ tune_autovacuum(dlq_name)
81
+ end
79
82
  true
80
83
  end
81
84
  end
@@ -446,12 +449,21 @@ module Pgbus
446
449
  @queues_created.compute_if_absent(full_name) do
447
450
  synchronized do
448
451
  @pgmq.create(full_name)
452
+ tune_autovacuum(full_name)
449
453
  @pgmq.enable_notify_insert(full_name, throttle_interval_ms: NOTIFY_THROTTLE_MS) if config.listen_notify
450
454
  end
451
455
  true
452
456
  end
453
457
  end
454
458
 
459
+ def tune_autovacuum(queue_name)
460
+ with_raw_connection do |conn|
461
+ conn.exec(AutovacuumTuning.sql_for_queue(queue_name))
462
+ end
463
+ rescue StandardError => e
464
+ Pgbus.logger.debug { "[Pgbus::Client] Autovacuum tuning failed for #{queue_name}: #{e.message}" }
465
+ end
466
+
455
467
  # Serialize PGMQ operations through a mutex when sharing a connection
456
468
  # with ActiveRecord (Proc path). When pgmq-ruby owns its own connections
457
469
  # (String/Hash path), the internal connection_pool handles concurrency.
data/lib/pgbus/engine.rb CHANGED
@@ -66,6 +66,29 @@ module Pgbus
66
66
  app.middleware.use Pgbus::Streams::WatermarkCacheMiddleware if Pgbus.configuration.streams_enabled
67
67
  end
68
68
 
69
+ # Make stream_source_element.js available to the host app's asset
70
+ # pipeline (Propshaft or Sprockets) so it can be included via
71
+ # `javascript_include_tag "pgbus/stream_source_element"` or pinned
72
+ # in importmap. When importmap-rails is loaded, auto-pin it so
73
+ # host apps get it without manual configuration.
74
+ initializer "pgbus.streams.assets" do |app|
75
+ if Pgbus.configuration.streams_enabled && app.config.respond_to?(:assets)
76
+ app.config.assets.precompile += %w[pgbus/stream_source_element.js]
77
+ end
78
+ end
79
+
80
+ initializer "pgbus.streams.importmap" do
81
+ if Pgbus.configuration.streams_enabled && defined?(::Importmap::Map)
82
+ ActiveSupport.on_load(:after_initialize) do
83
+ next unless Rails.application.respond_to?(:importmap)
84
+
85
+ Rails.application.importmap.pin(
86
+ "pgbus/stream_source_element", to: "pgbus/stream_source_element.js"
87
+ )
88
+ end
89
+ end
90
+ end
91
+
69
92
  # Install the Turbo::StreamsChannel patch after turbo-rails has been
70
93
  # loaded. The patch redirects broadcast_stream_to through Pgbus.stream
71
94
  # instead of ActionCable. When turbo-rails is not loaded, this is a