pgbus 0.9.4 → 0.9.6
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 +115 -0
- data/Rakefile +56 -3
- data/app/controllers/pgbus/dead_letter_controller.rb +5 -1
- data/app/helpers/pgbus/application_helper.rb +12 -2
- data/app/views/pgbus/dashboard/_processes_table.html.erb +1 -1
- data/app/views/pgbus/dashboard/_recent_failures.html.erb +1 -1
- data/app/views/pgbus/dashboard/_stats_cards.html.erb +1 -0
- data/app/views/pgbus/dead_letter/_messages_table.html.erb +33 -1
- data/app/views/pgbus/insights/show.html.erb +1 -1
- data/app/views/pgbus/jobs/_failed_table.html.erb +1 -1
- data/app/views/pgbus/processes/_processes_table.html.erb +1 -1
- data/app/views/pgbus/queues/show.html.erb +3 -0
- data/config/locales/da.yml +8 -0
- data/config/locales/de.yml +8 -0
- data/config/locales/en.yml +8 -0
- data/config/locales/es.yml +8 -0
- data/config/locales/fi.yml +8 -0
- data/config/locales/fr.yml +8 -0
- data/config/locales/it.yml +8 -0
- data/config/locales/ja.yml +8 -0
- data/config/locales/nb.yml +8 -0
- data/config/locales/nl.yml +8 -0
- data/config/locales/pt.yml +8 -0
- data/config/locales/sv.yml +8 -0
- data/lib/pgbus/cli.rb +16 -0
- data/lib/pgbus/client.rb +34 -7
- data/lib/pgbus/configuration.rb +17 -1
- data/lib/pgbus/integrations/appsignal/dashboard.json +353 -0
- data/lib/pgbus/integrations/appsignal/dashboards/pgbus_health.json +224 -85
- data/lib/pgbus/integrations/appsignal/dashboards/pgbus_streams.json +154 -63
- data/lib/pgbus/integrations/appsignal/dashboards/pgbus_throughput.json +218 -79
- data/lib/pgbus/integrations/appsignal/probe.rb +17 -2
- data/lib/pgbus/integrations/appsignal.rb +17 -0
- data/lib/pgbus/mcp/base_tool.rb +79 -0
- data/lib/pgbus/mcp/health_analyzer.rb +159 -0
- data/lib/pgbus/mcp/rack_app.rb +97 -0
- data/lib/pgbus/mcp/redactor.rb +72 -0
- data/lib/pgbus/mcp/runner.rb +73 -0
- data/lib/pgbus/mcp/server.rb +62 -0
- data/lib/pgbus/mcp/tools/dlq_detail_tool.rb +72 -0
- data/lib/pgbus/mcp/tools/dlq_tool.rb +48 -0
- data/lib/pgbus/mcp/tools/health_tool.rb +33 -0
- data/lib/pgbus/mcp/tools/job_detail_tool.rb +42 -0
- data/lib/pgbus/mcp/tools/jobs_tool.rb +56 -0
- data/lib/pgbus/mcp/tools/locks_tool.rb +28 -0
- data/lib/pgbus/mcp/tools/processes_tool.rb +32 -0
- data/lib/pgbus/mcp/tools/queue_detail_tool.rb +46 -0
- data/lib/pgbus/mcp/tools/queues_tool.rb +28 -0
- data/lib/pgbus/mcp/tools/recurring_tool.rb +27 -0
- data/lib/pgbus/mcp/tools/stats_tool.rb +40 -0
- data/lib/pgbus/mcp/tools/throughput_tool.rb +35 -0
- data/lib/pgbus/mcp.rb +55 -0
- data/lib/pgbus/process/heartbeat.rb +8 -2
- data/lib/pgbus/process/supervisor.rb +44 -0
- data/lib/pgbus/process/worker.rb +12 -1
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source.rb +40 -2
- data/lib/pgbus.rb +15 -1
- metadata +21 -1
data/config/locales/ja.yml
CHANGED
|
@@ -84,6 +84,7 @@ ja:
|
|
|
84
84
|
stats_cards:
|
|
85
85
|
enqueued: キューに追加済み
|
|
86
86
|
failed_dlq: 失敗 / DLQ
|
|
87
|
+
failed_dlq_labels: 失敗 / Dead Lettered
|
|
87
88
|
processes: プロセス
|
|
88
89
|
queues: キュー
|
|
89
90
|
recurring: 繰り返し
|
|
@@ -126,6 +127,7 @@ ja:
|
|
|
126
127
|
queue: 'キュー:'
|
|
127
128
|
visible_at: '表示日時:'
|
|
128
129
|
retry: 再試行
|
|
130
|
+
total_label: デッドレターキュー内のメッセージ
|
|
129
131
|
show:
|
|
130
132
|
back: DLQに戻る
|
|
131
133
|
discard: 破棄
|
|
@@ -225,6 +227,10 @@ ja:
|
|
|
225
227
|
bulk_select_all: すべて選択
|
|
226
228
|
bulk_select_row: "%{id}を選択"
|
|
227
229
|
bulk_selected: 選択済み
|
|
230
|
+
pagination:
|
|
231
|
+
next: 次へ
|
|
232
|
+
previous: 前へ
|
|
233
|
+
showing: "%{total} 件中 %{from}–%{to} 件を表示"
|
|
228
234
|
paused_badge: 一時停止中
|
|
229
235
|
queue_badge:
|
|
230
236
|
dlq: DLQ
|
|
@@ -235,6 +241,7 @@ ja:
|
|
|
235
241
|
status_badge:
|
|
236
242
|
healthy: 正常
|
|
237
243
|
stale: 期限切れ
|
|
244
|
+
stalled: 停滞
|
|
238
245
|
insights:
|
|
239
246
|
show:
|
|
240
247
|
charts:
|
|
@@ -476,6 +483,7 @@ ja:
|
|
|
476
483
|
resume: 再開
|
|
477
484
|
show:
|
|
478
485
|
arguments: 引数
|
|
486
|
+
back: キューに戻る
|
|
479
487
|
delete_confirm: このキューを完全に削除しますか?この操作は取り消せません。
|
|
480
488
|
delete_queue: キューを削除
|
|
481
489
|
depth: 深さ:
|
data/config/locales/nb.yml
CHANGED
|
@@ -84,6 +84,7 @@ nb:
|
|
|
84
84
|
stats_cards:
|
|
85
85
|
enqueued: I kø
|
|
86
86
|
failed_dlq: Mislyktes / DLQ
|
|
87
|
+
failed_dlq_labels: Mislyktes / Dead Lettered
|
|
87
88
|
processes: Prosesser
|
|
88
89
|
queues: Køer
|
|
89
90
|
recurring: Gjentakende
|
|
@@ -126,6 +127,7 @@ nb:
|
|
|
126
127
|
queue: 'Kø:'
|
|
127
128
|
visible_at: 'Synlig ved:'
|
|
128
129
|
retry: Prøv igjen
|
|
130
|
+
total_label: meldinger i dead letter-kø
|
|
129
131
|
show:
|
|
130
132
|
back: Tilbake til DLQ
|
|
131
133
|
discard: Forkast
|
|
@@ -225,6 +227,10 @@ nb:
|
|
|
225
227
|
bulk_select_all: Velg alle
|
|
226
228
|
bulk_select_row: Velg %{id}
|
|
227
229
|
bulk_selected: valgt
|
|
230
|
+
pagination:
|
|
231
|
+
next: Neste
|
|
232
|
+
previous: Forrige
|
|
233
|
+
showing: Viser %{from}–%{to} av %{total}
|
|
228
234
|
paused_badge: Pause
|
|
229
235
|
queue_badge:
|
|
230
236
|
dlq: DLQ
|
|
@@ -235,6 +241,7 @@ nb:
|
|
|
235
241
|
status_badge:
|
|
236
242
|
healthy: Sunn
|
|
237
243
|
stale: Utdatert
|
|
244
|
+
stalled: Fastlåst
|
|
238
245
|
insights:
|
|
239
246
|
show:
|
|
240
247
|
charts:
|
|
@@ -476,6 +483,7 @@ nb:
|
|
|
476
483
|
resume: Gjenoppta
|
|
477
484
|
show:
|
|
478
485
|
arguments: Argumenter
|
|
486
|
+
back: Tilbake til køer
|
|
479
487
|
delete_confirm: Slette denne køen permanent? Dette kan ikke angres.
|
|
480
488
|
delete_queue: Slett kø
|
|
481
489
|
depth: 'Dybde:'
|
data/config/locales/nl.yml
CHANGED
|
@@ -84,6 +84,7 @@ nl:
|
|
|
84
84
|
stats_cards:
|
|
85
85
|
enqueued: In de wachtrij geplaatst
|
|
86
86
|
failed_dlq: Mislukt / DLQ
|
|
87
|
+
failed_dlq_labels: Mislukt / Dead Lettered
|
|
87
88
|
processes: Processen
|
|
88
89
|
queues: Wachtrijen
|
|
89
90
|
recurring: Terugkerend
|
|
@@ -126,6 +127,7 @@ nl:
|
|
|
126
127
|
queue: 'Wachtrij:'
|
|
127
128
|
visible_at: 'Zichtbaar op:'
|
|
128
129
|
retry: Opnieuw proberen
|
|
130
|
+
total_label: berichten in dead letter-wachtrij
|
|
129
131
|
show:
|
|
130
132
|
back: Terug naar DLQ
|
|
131
133
|
discard: Verwerpen
|
|
@@ -225,6 +227,10 @@ nl:
|
|
|
225
227
|
bulk_select_all: Alles selecteren
|
|
226
228
|
bulk_select_row: Selecteer %{id}
|
|
227
229
|
bulk_selected: geselecteerd
|
|
230
|
+
pagination:
|
|
231
|
+
next: Volgende
|
|
232
|
+
previous: Vorige
|
|
233
|
+
showing: "%{from}–%{to} van %{total} weergegeven"
|
|
228
234
|
paused_badge: Gepauzeerd
|
|
229
235
|
queue_badge:
|
|
230
236
|
dlq: DLQ
|
|
@@ -235,6 +241,7 @@ nl:
|
|
|
235
241
|
status_badge:
|
|
236
242
|
healthy: Gezond
|
|
237
243
|
stale: Verouderd
|
|
244
|
+
stalled: Vastgelopen
|
|
238
245
|
insights:
|
|
239
246
|
show:
|
|
240
247
|
charts:
|
|
@@ -476,6 +483,7 @@ nl:
|
|
|
476
483
|
resume: Hervatten
|
|
477
484
|
show:
|
|
478
485
|
arguments: Argumenten
|
|
486
|
+
back: Terug naar wachtrijen
|
|
479
487
|
delete_confirm: Deze wachtrij permanent verwijderen? Dit kan niet ongedaan worden gemaakt.
|
|
480
488
|
delete_queue: Wachtrij verwijderen
|
|
481
489
|
depth: 'Diepte:'
|
data/config/locales/pt.yml
CHANGED
|
@@ -84,6 +84,7 @@ pt:
|
|
|
84
84
|
stats_cards:
|
|
85
85
|
enqueued: Enfileirado
|
|
86
86
|
failed_dlq: Falhou / DLQ
|
|
87
|
+
failed_dlq_labels: Falhados / Dead Lettered
|
|
87
88
|
processes: Processos
|
|
88
89
|
queues: Filas
|
|
89
90
|
recurring: Recorrente
|
|
@@ -126,6 +127,7 @@ pt:
|
|
|
126
127
|
queue: 'Fila:'
|
|
127
128
|
visible_at: 'Visível em:'
|
|
128
129
|
retry: Tentar novamente
|
|
130
|
+
total_label: mensagens na fila de mensagens mortas
|
|
129
131
|
show:
|
|
130
132
|
back: Voltar para DLQ
|
|
131
133
|
discard: Descartar
|
|
@@ -225,6 +227,10 @@ pt:
|
|
|
225
227
|
bulk_select_all: Selecionar todos
|
|
226
228
|
bulk_select_row: Selecionar %{id}
|
|
227
229
|
bulk_selected: selecionado
|
|
230
|
+
pagination:
|
|
231
|
+
next: Próximo
|
|
232
|
+
previous: Anterior
|
|
233
|
+
showing: Mostrando %{from}–%{to} de %{total}
|
|
228
234
|
paused_badge: Pausado
|
|
229
235
|
queue_badge:
|
|
230
236
|
dlq: DLQ
|
|
@@ -235,6 +241,7 @@ pt:
|
|
|
235
241
|
status_badge:
|
|
236
242
|
healthy: Saudável
|
|
237
243
|
stale: Obsoleto
|
|
244
|
+
stalled: Bloqueado
|
|
238
245
|
insights:
|
|
239
246
|
show:
|
|
240
247
|
charts:
|
|
@@ -476,6 +483,7 @@ pt:
|
|
|
476
483
|
resume: Retomar
|
|
477
484
|
show:
|
|
478
485
|
arguments: Argumentos
|
|
486
|
+
back: Voltar às filas
|
|
479
487
|
delete_confirm: Excluir permanentemente esta fila? Esta ação não pode ser desfeita.
|
|
480
488
|
delete_queue: Excluir fila
|
|
481
489
|
depth: 'Profundidade:'
|
data/config/locales/sv.yml
CHANGED
|
@@ -84,6 +84,7 @@ sv:
|
|
|
84
84
|
stats_cards:
|
|
85
85
|
enqueued: Inlagda
|
|
86
86
|
failed_dlq: Misslyckade / DLQ
|
|
87
|
+
failed_dlq_labels: Misslyckade / Dead Lettered
|
|
87
88
|
processes: Processer
|
|
88
89
|
queues: Köer
|
|
89
90
|
recurring: Återkommande
|
|
@@ -126,6 +127,7 @@ sv:
|
|
|
126
127
|
queue: 'Kö:'
|
|
127
128
|
visible_at: 'Synlig vid:'
|
|
128
129
|
retry: Försök igen
|
|
130
|
+
total_label: meddelanden i dead letter-kö
|
|
129
131
|
show:
|
|
130
132
|
back: Tillbaka till DLQ
|
|
131
133
|
discard: Kassera
|
|
@@ -225,6 +227,10 @@ sv:
|
|
|
225
227
|
bulk_select_all: Markera alla
|
|
226
228
|
bulk_select_row: Markera %{id}
|
|
227
229
|
bulk_selected: valda
|
|
230
|
+
pagination:
|
|
231
|
+
next: Nästa
|
|
232
|
+
previous: Föregående
|
|
233
|
+
showing: Visar %{from}–%{to} av %{total}
|
|
228
234
|
paused_badge: Pausad
|
|
229
235
|
queue_badge:
|
|
230
236
|
dlq: DLQ
|
|
@@ -235,6 +241,7 @@ sv:
|
|
|
235
241
|
status_badge:
|
|
236
242
|
healthy: Hälsosam
|
|
237
243
|
stale: Föråldrad
|
|
244
|
+
stalled: Fastlåst
|
|
238
245
|
insights:
|
|
239
246
|
show:
|
|
240
247
|
charts:
|
|
@@ -476,6 +483,7 @@ sv:
|
|
|
476
483
|
resume: Återuppta
|
|
477
484
|
show:
|
|
478
485
|
arguments: Argument
|
|
486
|
+
back: Tillbaka till köer
|
|
479
487
|
delete_confirm: Ta bort denna kö permanent? Detta kan inte ångras.
|
|
480
488
|
delete_queue: Ta bort kö
|
|
481
489
|
depth: 'Djup:'
|
data/lib/pgbus/cli.rb
CHANGED
|
@@ -16,6 +16,8 @@ module Pgbus
|
|
|
16
16
|
show_status
|
|
17
17
|
when "queues"
|
|
18
18
|
list_queues
|
|
19
|
+
when "mcp"
|
|
20
|
+
start_mcp_server
|
|
19
21
|
when "version"
|
|
20
22
|
puts "pgbus #{Pgbus::VERSION}"
|
|
21
23
|
when "help", "--help", "-h"
|
|
@@ -132,6 +134,13 @@ module Pgbus
|
|
|
132
134
|
end
|
|
133
135
|
end
|
|
134
136
|
|
|
137
|
+
# Boots the read-only MCP diagnostic server over stdio. Loaded lazily so
|
|
138
|
+
# the optional `mcp` gem is only required when this command is invoked.
|
|
139
|
+
def start_mcp_server
|
|
140
|
+
Pgbus::MCP.load!
|
|
141
|
+
Pgbus::MCP::Runner.run
|
|
142
|
+
end
|
|
143
|
+
|
|
135
144
|
def list_queues
|
|
136
145
|
Pgbus.client.list_queues
|
|
137
146
|
metrics = Pgbus.client.metrics
|
|
@@ -154,6 +163,7 @@ module Pgbus
|
|
|
154
163
|
start Start the Pgbus supervisor (workers + dispatcher)
|
|
155
164
|
status Show running Pgbus processes
|
|
156
165
|
queues List queues with metrics
|
|
166
|
+
mcp Start the read-only MCP diagnostic server over stdio
|
|
157
167
|
version Show version
|
|
158
168
|
help Show this help
|
|
159
169
|
|
|
@@ -172,6 +182,12 @@ module Pgbus
|
|
|
172
182
|
pattern)
|
|
173
183
|
--execution-mode Execution mode: threads (default) or async
|
|
174
184
|
(fiber-based, lower connection usage)
|
|
185
|
+
|
|
186
|
+
Environment for `mcp`:
|
|
187
|
+
PGBUS_MCP_TOKEN If set, PGBUS_MCP_AUTH_TOKEN must match for
|
|
188
|
+
the server to start (optional token gate).
|
|
189
|
+
PGBUS_MCP_ALLOW_PAYLOADS Truthy to let tools return raw message
|
|
190
|
+
bodies/headers (off by default; redacted).
|
|
175
191
|
HELP
|
|
176
192
|
end
|
|
177
193
|
end
|
data/lib/pgbus/client.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "timeout"
|
|
4
5
|
require_relative "client/read_after"
|
|
5
6
|
require_relative "client/ensure_stream_queue"
|
|
6
7
|
require_relative "client/notify_stream"
|
|
@@ -110,7 +111,7 @@ module Pgbus
|
|
|
110
111
|
full_name = config.queue_name(queue_name)
|
|
111
112
|
Instrumentation.instrument("pgbus.client.read_message", queue: full_name) do
|
|
112
113
|
with_stale_connection_retry do
|
|
113
|
-
synchronized { @pgmq.read(full_name, vt: vt || config.visibility_timeout) }
|
|
114
|
+
synchronized { with_read_timeout { @pgmq.read(full_name, vt: vt || config.visibility_timeout) } }
|
|
114
115
|
end
|
|
115
116
|
end
|
|
116
117
|
end
|
|
@@ -119,7 +120,7 @@ module Pgbus
|
|
|
119
120
|
full_name = config.queue_name(queue_name)
|
|
120
121
|
Instrumentation.instrument("pgbus.client.read_batch", queue: full_name, qty: qty) do
|
|
121
122
|
with_stale_connection_retry do
|
|
122
|
-
synchronized { @pgmq.read_batch(full_name, vt: vt || config.visibility_timeout, qty: qty) }
|
|
123
|
+
synchronized { with_read_timeout { @pgmq.read_batch(full_name, vt: vt || config.visibility_timeout, qty: qty) } }
|
|
123
124
|
end
|
|
124
125
|
end
|
|
125
126
|
end
|
|
@@ -141,7 +142,7 @@ module Pgbus
|
|
|
141
142
|
|
|
142
143
|
msgs = Instrumentation.instrument("pgbus.client.read_batch", queue: pq_name, qty: remaining) do
|
|
143
144
|
with_stale_connection_retry do
|
|
144
|
-
synchronized { @pgmq.read_batch(pq_name, vt: vt || config.visibility_timeout, qty: remaining) }
|
|
145
|
+
synchronized { with_read_timeout { @pgmq.read_batch(pq_name, vt: vt || config.visibility_timeout, qty: remaining) } }
|
|
145
146
|
end
|
|
146
147
|
end || []
|
|
147
148
|
|
|
@@ -180,7 +181,9 @@ module Pgbus
|
|
|
180
181
|
Instrumentation.instrument("pgbus.client.read_multi", queues: full_names, qty: qty, limit: limit) do
|
|
181
182
|
with_stale_connection_retry do
|
|
182
183
|
synchronized do
|
|
183
|
-
|
|
184
|
+
with_read_timeout do
|
|
185
|
+
@pgmq.read_multi(full_names, vt: vt || config.visibility_timeout, qty: qty, limit: limit)
|
|
186
|
+
end
|
|
184
187
|
end
|
|
185
188
|
end
|
|
186
189
|
end
|
|
@@ -357,7 +360,7 @@ module Pgbus
|
|
|
357
360
|
full_name = config.queue_name(queue_name)
|
|
358
361
|
Instrumentation.instrument("pgbus.client.read_grouped", queue: full_name, qty: qty) do
|
|
359
362
|
with_stale_connection_retry do
|
|
360
|
-
synchronized { @pgmq.read_grouped(full_name, vt: vt || config.visibility_timeout, qty: qty) }
|
|
363
|
+
synchronized { with_read_timeout { @pgmq.read_grouped(full_name, vt: vt || config.visibility_timeout, qty: qty) } }
|
|
361
364
|
end
|
|
362
365
|
end
|
|
363
366
|
end
|
|
@@ -366,7 +369,7 @@ module Pgbus
|
|
|
366
369
|
full_name = config.queue_name(queue_name)
|
|
367
370
|
Instrumentation.instrument("pgbus.client.read_grouped_rr", queue: full_name, qty: qty) do
|
|
368
371
|
with_stale_connection_retry do
|
|
369
|
-
synchronized { @pgmq.read_grouped_rr(full_name, vt: vt || config.visibility_timeout, qty: qty) }
|
|
372
|
+
synchronized { with_read_timeout { @pgmq.read_grouped_rr(full_name, vt: vt || config.visibility_timeout, qty: qty) } }
|
|
370
373
|
end
|
|
371
374
|
end
|
|
372
375
|
end
|
|
@@ -374,7 +377,7 @@ module Pgbus
|
|
|
374
377
|
def read_grouped_head(queue_name, qty:, vt: nil)
|
|
375
378
|
full_name = config.queue_name(queue_name)
|
|
376
379
|
with_stale_connection_retry do
|
|
377
|
-
synchronized { @pgmq.read_grouped_head(full_name, vt: vt || config.visibility_timeout, qty: qty) }
|
|
380
|
+
synchronized { with_read_timeout { @pgmq.read_grouped_head(full_name, vt: vt || config.visibility_timeout, qty: qty) } }
|
|
378
381
|
end
|
|
379
382
|
end
|
|
380
383
|
|
|
@@ -696,6 +699,30 @@ module Pgbus
|
|
|
696
699
|
# connection was dead *before* pgmq-ruby tried to use it, so no SQL was
|
|
697
700
|
# ever sent. Mid-flight errors like "server closed the connection" are
|
|
698
701
|
# excluded from the pattern list for this reason.
|
|
702
|
+
# Bound a read at config.read_timeout so a dead socket raises
|
|
703
|
+
# Pgbus::ReadTimeoutError instead of blocking the worker loop forever.
|
|
704
|
+
#
|
|
705
|
+
# MUST wrap only the bare `@pgmq.read*` call, sitting *inside* both
|
|
706
|
+
# `synchronized` and `with_stale_connection_retry`:
|
|
707
|
+
#
|
|
708
|
+
# with_stale_connection_retry { synchronized { with_read_timeout { @pgmq.read* } } }
|
|
709
|
+
#
|
|
710
|
+
# Two reasons for this nesting:
|
|
711
|
+
# 1. On the shared-connection path @pgmq_mutex serializes all reads.
|
|
712
|
+
# The timeout clock must start only after the mutex is acquired,
|
|
713
|
+
# otherwise a thread queued behind another read is charged for the
|
|
714
|
+
# wait and raises a false ReadTimeoutError for a socket it never
|
|
715
|
+
# touched.
|
|
716
|
+
# 2. with_stale_connection_retry can retry once; with the timeout
|
|
717
|
+
# inside, each socket attempt gets its own full timeout budget
|
|
718
|
+
# rather than sharing one across both attempts.
|
|
719
|
+
def with_read_timeout(&)
|
|
720
|
+
timeout = config.read_timeout
|
|
721
|
+
return yield unless timeout&.positive?
|
|
722
|
+
|
|
723
|
+
Timeout.timeout(timeout, Pgbus::ReadTimeoutError, &)
|
|
724
|
+
end
|
|
725
|
+
|
|
699
726
|
def with_stale_connection_retry
|
|
700
727
|
attempts = 0
|
|
701
728
|
begin
|
data/lib/pgbus/configuration.rb
CHANGED
|
@@ -26,6 +26,12 @@ module Pgbus
|
|
|
26
26
|
# Worker recycling
|
|
27
27
|
attr_accessor :max_jobs_per_worker, :max_memory_mb, :max_worker_lifetime
|
|
28
28
|
|
|
29
|
+
# Liveness probe: supervisor kills a worker whose claim loop has not
|
|
30
|
+
# advanced for longer than stall_threshold seconds (default 90).
|
|
31
|
+
# read_timeout caps how long a single PGMQ read can block (default 30s),
|
|
32
|
+
# so a dead socket raises instead of parking the loop forever.
|
|
33
|
+
attr_accessor :stall_threshold, :read_timeout
|
|
34
|
+
|
|
29
35
|
# Dispatcher settings
|
|
30
36
|
attr_accessor :dispatch_interval
|
|
31
37
|
|
|
@@ -150,6 +156,9 @@ module Pgbus
|
|
|
150
156
|
@max_memory_mb = nil
|
|
151
157
|
@max_worker_lifetime = nil
|
|
152
158
|
|
|
159
|
+
@stall_threshold = 90
|
|
160
|
+
@read_timeout = 30
|
|
161
|
+
|
|
153
162
|
@dispatch_interval = 1.0
|
|
154
163
|
|
|
155
164
|
@circuit_breaker_enabled = true
|
|
@@ -207,7 +216,7 @@ module Pgbus
|
|
|
207
216
|
@web_per_page = 25
|
|
208
217
|
@web_live_updates = true
|
|
209
218
|
@web_data_source = nil
|
|
210
|
-
@insights_default_minutes =
|
|
219
|
+
@insights_default_minutes = 60 # 1 hour
|
|
211
220
|
@base_controller_class = "::ActionController::Base"
|
|
212
221
|
@return_to_app_url = nil
|
|
213
222
|
@metrics_enabled = true
|
|
@@ -374,6 +383,13 @@ module Pgbus
|
|
|
374
383
|
raise ArgumentError, "retry_backoff_jitter must be between 0 and 1"
|
|
375
384
|
end
|
|
376
385
|
|
|
386
|
+
unless stall_threshold.nil? || (stall_threshold.is_a?(Numeric) && stall_threshold.positive?)
|
|
387
|
+
raise ArgumentError, "stall_threshold must be a positive number or nil to disable"
|
|
388
|
+
end
|
|
389
|
+
unless read_timeout.nil? || (read_timeout.is_a?(Numeric) && read_timeout.positive?)
|
|
390
|
+
raise ArgumentError, "read_timeout must be a positive number or nil to disable"
|
|
391
|
+
end
|
|
392
|
+
|
|
377
393
|
# Validate global execution_mode
|
|
378
394
|
ExecutionPools.normalize_mode(execution_mode)
|
|
379
395
|
|