pgbus 0.17.1 → 0.17.2
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 +38 -0
- data/README.md +48 -13
- data/app/controllers/concerns/pgbus/job_listing.rb +37 -0
- data/app/controllers/concerns/pgbus/process_listing.rb +17 -0
- data/app/controllers/pgbus/application_controller.rb +5 -2
- data/app/controllers/pgbus/batches_controller.rb +4 -1
- data/app/controllers/pgbus/dashboard_controller.rb +20 -6
- data/app/controllers/pgbus/dead_letter_controller.rb +27 -3
- data/app/controllers/pgbus/events_controller.rb +52 -3
- data/app/controllers/pgbus/insights_controller.rb +19 -1
- data/app/controllers/pgbus/jobs_controller.rb +45 -26
- data/app/controllers/pgbus/locks_controller.rb +7 -2
- data/app/controllers/pgbus/outbox_controller.rb +4 -1
- data/app/controllers/pgbus/processes_controller.rb +3 -1
- data/app/controllers/pgbus/queues_controller.rb +16 -4
- data/app/controllers/pgbus/recurring_tasks_controller.rb +5 -7
- data/app/frontend/pgbus/modules/charts.js +119 -77
- data/app/frontend/pgbus/style.css +1 -1
- data/app/frontend/pgbus/tailwind.css +18 -0
- data/app/helpers/pgbus/application_helper.rb +155 -113
- data/app/helpers/pgbus/button_helper.rb +88 -0
- data/app/helpers/pgbus/dashboard_helper.rb +157 -0
- data/app/helpers/pgbus/events_helper.rb +40 -0
- data/app/helpers/pgbus/insights_helper.rb +39 -0
- data/app/helpers/pgbus/processes_helper.rb +79 -0
- data/app/views/pgbus/batches/_batches_table.html.erb +16 -13
- data/app/views/pgbus/batches/show.html.erb +3 -4
- data/app/views/pgbus/dashboard/_processes_table.html.erb +11 -11
- data/app/views/pgbus/dashboard/_queue_health.html.erb +42 -51
- data/app/views/pgbus/dashboard/_queues_table.html.erb +18 -16
- data/app/views/pgbus/dashboard/_recent_failures.html.erb +16 -12
- data/app/views/pgbus/dashboard/_stats_cards.html.erb +70 -36
- data/app/views/pgbus/dashboard/show.html.erb +1 -1
- data/app/views/pgbus/dead_letter/_error.html.erb +13 -0
- data/app/views/pgbus/dead_letter/_messages_table.html.erb +37 -96
- data/app/views/pgbus/dead_letter/_row.html.erb +75 -0
- data/app/views/pgbus/dead_letter/index.html.erb +6 -9
- data/app/views/pgbus/dead_letter/show.html.erb +37 -21
- data/app/views/pgbus/events/_list.html.erb +55 -0
- data/app/views/pgbus/events/_processed_table.html.erb +45 -0
- data/app/views/pgbus/events/_replay.html.erb +10 -0
- data/app/views/pgbus/events/_row.html.erb +162 -0
- data/app/views/pgbus/events/_tabs.html.erb +13 -0
- data/app/views/pgbus/events/index.html.erb +27 -48
- data/app/views/pgbus/events/show.html.erb +25 -7
- data/app/views/pgbus/insights/_chart_card.html.erb +21 -0
- data/app/views/pgbus/insights/_latency_table.html.erb +20 -0
- data/app/views/pgbus/insights/_status_table.html.erb +19 -0
- data/app/views/pgbus/insights/_throughput_table.html.erb +18 -0
- data/app/views/pgbus/insights/show.html.erb +83 -100
- data/app/views/pgbus/jobs/_list.html.erb +64 -0
- data/app/views/pgbus/jobs/_row.html.erb +107 -0
- data/app/views/pgbus/jobs/_tabs.html.erb +14 -0
- data/app/views/pgbus/jobs/index.html.erb +10 -10
- data/app/views/pgbus/jobs/show.html.erb +18 -20
- data/app/views/pgbus/locks/_concurrency.html.erb +25 -23
- data/app/views/pgbus/locks/_uniqueness.html.erb +20 -22
- data/app/views/pgbus/outbox/index.html.erb +30 -27
- data/app/views/pgbus/processes/_processes_table.html.erb +6 -25
- data/app/views/pgbus/processes/_row.html.erb +48 -0
- data/app/views/pgbus/processes/_status.html.erb +4 -0
- data/app/views/pgbus/queues/_queues_list.html.erb +28 -32
- data/app/views/pgbus/queues/show.html.erb +69 -118
- data/app/views/pgbus/recurring_tasks/_tasks_table.html.erb +75 -76
- data/app/views/pgbus/recurring_tasks/index.html.erb +1 -1
- data/app/views/pgbus/recurring_tasks/show.html.erb +45 -51
- data/app/views/pgbus/shared/_empty_row.html.erb +2 -0
- data/app/views/pgbus/shared/_pager.html.erb +34 -0
- data/config/i18n-tasks.yml +11 -2
- data/config/locales/da.yml +405 -113
- data/config/locales/de.yml +405 -113
- data/config/locales/en.yml +405 -113
- data/config/locales/es.yml +404 -112
- data/config/locales/fi.yml +404 -112
- data/config/locales/fr.yml +406 -114
- data/config/locales/it.yml +405 -113
- data/config/locales/ja.yml +405 -113
- data/config/locales/nb.yml +405 -113
- data/config/locales/nl.yml +405 -113
- data/config/locales/pt.yml +406 -114
- data/config/locales/sv.yml +404 -112
- data/lib/generators/pgbus/templates/initializer.rb.erb +4 -0
- data/lib/pgbus/active_job/executor.rb +16 -6
- data/lib/pgbus/cli/dlq.rb +32 -5
- data/lib/pgbus/client.rb +4 -2
- data/lib/pgbus/configuration.rb +47 -2
- data/lib/pgbus/dead_letter_header.rb +129 -0
- data/lib/pgbus/doctor.rb +8 -4
- data/lib/pgbus/event_bus/handler.rb +18 -11
- data/lib/pgbus/event_bus/registry.rb +6 -0
- data/lib/pgbus/failed_event_recorder.rb +34 -0
- data/lib/pgbus/instrumentation.rb +2 -1
- data/lib/pgbus/mcp/base_tool.rb +25 -0
- data/lib/pgbus/mcp/tools/concurrency_tool.rb +23 -4
- data/lib/pgbus/mcp/tools/dlq_detail_tool.rb +4 -2
- data/lib/pgbus/mcp/tools/dlq_tool.rb +10 -4
- data/lib/pgbus/mcp/tools/locks_tool.rb +23 -5
- data/lib/pgbus/mcp/tools/recurring_tool.rb +33 -4
- data/lib/pgbus/outbox/poller.rb +1 -1
- data/lib/pgbus/process/consumer.rb +53 -3
- data/lib/pgbus/process/dispatcher.rb +1 -1
- data/lib/pgbus/process/supervisor.rb +32 -11
- data/lib/pgbus/process/worker.rb +45 -8
- data/lib/pgbus/recurring/scheduler.rb +2 -1
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source/dashboard_signals.rb +170 -0
- data/lib/pgbus/web/data_source/dead_letter.rb +142 -0
- data/lib/pgbus/web/data_source/event_list.rb +161 -0
- data/lib/pgbus/web/data_source/job_list.rb +323 -0
- data/lib/pgbus/web/data_source/list_counts.rb +80 -0
- data/lib/pgbus/web/data_source/process_list.rb +69 -0
- data/lib/pgbus/web/data_source/queue_summary.rb +122 -0
- data/lib/pgbus/web/data_source.rb +132 -254
- data/lib/pgbus/web/dead_letter_reason.rb +81 -0
- data/lib/pgbus/web/event_state.rb +71 -0
- data/lib/pgbus/web/health_app.rb +7 -3
- data/lib/pgbus/web/health_verdict.rb +78 -0
- data/lib/pgbus/web/insights_charts.rb +84 -0
- data/lib/pgbus/web/job_state.rb +111 -0
- data/lib/pgbus/web/process_activity.rb +97 -0
- data/lib/pgbus/web/process_state.rb +187 -0
- data/lib/pgbus/web/queue_summary.rb +104 -0
- data/lib/pgbus/web/time_format.rb +128 -0
- metadata +43 -4
- data/app/views/pgbus/events/_pending_table.html.erb +0 -169
- data/app/views/pgbus/jobs/_enqueued_table.html.erb +0 -118
- data/app/views/pgbus/jobs/_failed_table.html.erb +0 -76
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pgbus
|
|
4
|
+
module Web
|
|
5
|
+
class DataSource
|
|
6
|
+
# Row totals for the dashboard's paged lists (issue #496). list_count
|
|
7
|
+
# stops at COUNT_CAP + 1 rows, so a table with millions of rows costs no
|
|
8
|
+
# more than one with ten thousand; past the cap the pager shows "10,000+".
|
|
9
|
+
# The same bound JobList uses for its state tabs. batches_count and
|
|
10
|
+
# recurring_tasks_count are exact (summary_stats' badge reads the latter);
|
|
11
|
+
# they predate the pagers and live here to keep data_source.rb small.
|
|
12
|
+
module ListCounts
|
|
13
|
+
COUNT_CAP = 10_000
|
|
14
|
+
|
|
15
|
+
Count = Data.define(:total, :capped) do
|
|
16
|
+
def capped? = capped
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
EMPTY_COUNT = Count.new(total: 0, capped: false)
|
|
20
|
+
|
|
21
|
+
# Semaphores and parked jobs, FULL OUTER JOINed: a key can have parked
|
|
22
|
+
# rows and no semaphore (its holder died and the sweep removed the row)
|
|
23
|
+
# or a semaphore and nothing parked. Shared with concurrency_keys.
|
|
24
|
+
CONCURRENCY_KEYS_FROM = <<~SQL
|
|
25
|
+
FROM pgbus_semaphores s
|
|
26
|
+
FULL OUTER JOIN (
|
|
27
|
+
SELECT concurrency_key, COUNT(*) AS parked_count, MIN(created_at) AS oldest_parked_at
|
|
28
|
+
FROM pgbus_blocked_executions
|
|
29
|
+
GROUP BY concurrency_key
|
|
30
|
+
) b ON s.key = b.concurrency_key
|
|
31
|
+
SQL
|
|
32
|
+
|
|
33
|
+
LIST_MODELS = {
|
|
34
|
+
batches: -> { BatchEntry },
|
|
35
|
+
job_locks: -> { UniquenessKey },
|
|
36
|
+
outbox: -> { OutboxEntry },
|
|
37
|
+
processed_events: -> { ProcessedEvent },
|
|
38
|
+
recurring_tasks: -> { RecurringTask }
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
# list – :batches, :job_locks, :concurrency_keys, :outbox, :processed_events or :recurring_tasks.
|
|
42
|
+
def list_count(list)
|
|
43
|
+
raise ArgumentError, "unknown list: #{list.inspect}" unless list == :concurrency_keys || LIST_MODELS.key?(list)
|
|
44
|
+
|
|
45
|
+
bounded_count(list)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def batches_count
|
|
49
|
+
BatchEntry.count
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
Pgbus.logger.debug { "[Pgbus::Web] Error counting batches: #{e.message}" }
|
|
52
|
+
0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def recurring_tasks_count
|
|
56
|
+
RecurringTask.count
|
|
57
|
+
rescue StandardError => e
|
|
58
|
+
Pgbus.logger.debug { "[Pgbus::Web] Error counting recurring tasks: #{e.message}" }
|
|
59
|
+
0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def bounded_count(list)
|
|
65
|
+
rows = list == :concurrency_keys ? concurrency_keys_probe : LIST_MODELS.fetch(list).call.limit(COUNT_CAP + 1).count
|
|
66
|
+
Count.new(total: [rows.to_i, COUNT_CAP].min, capped: rows.to_i > COUNT_CAP)
|
|
67
|
+
rescue StandardError => e
|
|
68
|
+
Pgbus.logger.debug { "[Pgbus::Web] Error counting #{list}: #{e.message}" }
|
|
69
|
+
EMPTY_COUNT
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def concurrency_keys_probe
|
|
73
|
+
connection.select_value(<<~SQL, "Pgbus Concurrency Keys Count")
|
|
74
|
+
SELECT COUNT(*) FROM (SELECT 1 #{CONCURRENCY_KEYS_FROM} LIMIT #{COUNT_CAP + 1}) c
|
|
75
|
+
SQL
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pgbus
|
|
4
|
+
module Web
|
|
5
|
+
class DataSource
|
|
6
|
+
# The Processes page's rows and the context ProcessState needs to put
|
|
7
|
+
# them in words (issue #493). Every status in one result set is derived
|
|
8
|
+
# against one ProcessState::Thresholds, so one now.
|
|
9
|
+
module ProcessList
|
|
10
|
+
# thresholds: pass the ones the caller puts the rows in words with, so
|
|
11
|
+
# badge and sentence share one now.
|
|
12
|
+
def processes(thresholds: process_thresholds)
|
|
13
|
+
process_rows.map { |r| format_process(r, thresholds) }
|
|
14
|
+
rescue StandardError => e
|
|
15
|
+
Pgbus.logger.debug { "[Pgbus::Web] Error fetching processes: #{e.message}" }
|
|
16
|
+
[]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The dashboard host's config: the stall limits the page states are
|
|
20
|
+
# this host's stall_threshold, as the badge always was.
|
|
21
|
+
def process_thresholds(now: Time.now)
|
|
22
|
+
config = Pgbus.configuration
|
|
23
|
+
ProcessState::Thresholds.new(
|
|
24
|
+
now: now, alive_threshold: Process::Heartbeat::ALIVE_THRESHOLD, stall_threshold: config.stall_threshold,
|
|
25
|
+
dispatch_interval: config.dispatch_interval, recurring_schedule_interval: config.recurring_schedule_interval,
|
|
26
|
+
polling_interval: config.polling_interval, notify_fallback_poll: Process::Consumer::NOTIFY_FALLBACK_POLL_SECONDS,
|
|
27
|
+
notify_wakeup: config.worker_notify_wakeup?, reap_interval: Process::Dispatcher::REAP_INTERVAL
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def process_context(rows:, thresholds: process_thresholds)
|
|
32
|
+
ProcessState.context_for(rows, thresholds)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# The raw rows, memoized per instance like queues_with_metrics (cleared
|
|
38
|
+
# by reset_cache!): the home page reads them for the stats, the signals,
|
|
39
|
+
# the health verdict, the queue lines and the panel (issue #492). Only
|
|
40
|
+
# the rows: each caller derives statuses against its own thresholds.
|
|
41
|
+
def process_rows
|
|
42
|
+
@process_rows ||= connection.select_all("SELECT * FROM pgbus_processes ORDER BY kind, created_at").to_a
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def format_process(row, thresholds)
|
|
46
|
+
heartbeat = JobState.time(row["last_heartbeat_at"])
|
|
47
|
+
metadata = row["metadata"].is_a?(String) ? JSON.parse(row["metadata"]) : row["metadata"]
|
|
48
|
+
status = ProcessState.derive(kind: row["kind"], metadata: metadata, heartbeat_at: heartbeat,
|
|
49
|
+
thresholds: thresholds)
|
|
50
|
+
started_at = metadata.is_a?(Hash) && metadata["started_at"]
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
id: row["id"].to_i,
|
|
54
|
+
kind: row["kind"],
|
|
55
|
+
hostname: row["hostname"],
|
|
56
|
+
pid: row["pid"].to_i,
|
|
57
|
+
metadata: metadata,
|
|
58
|
+
last_heartbeat_at: heartbeat,
|
|
59
|
+
healthy: status == :healthy,
|
|
60
|
+
status: status,
|
|
61
|
+
created_at: row["created_at"],
|
|
62
|
+
supervisor_pid: metadata.is_a?(Hash) ? metadata["supervisor_pid"] : nil,
|
|
63
|
+
started_at: started_at ? Time.at(started_at.to_f) : nil
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pgbus
|
|
4
|
+
module Web
|
|
5
|
+
class DataSource
|
|
6
|
+
# The facts behind a queue page's summary in words (issue #491), turned
|
|
7
|
+
# into sentences by Pgbus::Web::QueueSummary. Both methods take the
|
|
8
|
+
# physical queue name the page is for.
|
|
9
|
+
module QueueSummary
|
|
10
|
+
RUNNING = { paused: false, reason: nil, paused_at: nil, resumes_at: nil, trip_count: 0 }.freeze
|
|
11
|
+
|
|
12
|
+
# Pause state is kept per logical queue, so every priority level and
|
|
13
|
+
# the bare table share it.
|
|
14
|
+
def queue_pause_state(name)
|
|
15
|
+
pause_state_of(QueueState.find_by(queue_name: logical_queue_name(name)))
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
Pgbus.logger.error { "[Pgbus::Web] Error reading pause state for #{name}: #{e.class}: #{e.message}" }
|
|
18
|
+
RUNNING
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# { physical name => pause state } for many queues in one query (the
|
|
22
|
+
# home page's queues table, issue #492). Raises: the caller degrades.
|
|
23
|
+
def queue_pause_states(names)
|
|
24
|
+
states = QueueState.where(queue_name: names.map { |n| logical_queue_name(n) }.uniq).index_by(&:queue_name)
|
|
25
|
+
names.to_h { |name| [name, pause_state_of(states[logical_queue_name(name)])] }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# healthy: and streams: let a caller describing many queues load the
|
|
29
|
+
# process rows and the stream registry once (issue #492).
|
|
30
|
+
def queue_drainers(name, healthy: processes.select { |p| p[:healthy] }, streams: stream_queue_names)
|
|
31
|
+
table = name.to_s.delete_suffix(Pgbus::DEAD_LETTER_SUFFIX)
|
|
32
|
+
level = priority_level_of(table)
|
|
33
|
+
logical = level ? logical_queue_name(table) : table.delete_prefix("#{Pgbus.configuration.queue_prefix}_")
|
|
34
|
+
capsules, wildcard = draining_capsules(name)
|
|
35
|
+
{
|
|
36
|
+
logical: logical, capsules: capsules, wildcard: wildcard,
|
|
37
|
+
handler: handler_queue_physical_names.include?(name), stream: streams.include?(name),
|
|
38
|
+
live_workers: healthy.count { |p| p[:kind].to_s == "worker" && worker_drains?(p, logical) },
|
|
39
|
+
live_consumers: healthy.count { |p| p[:kind].to_s == "consumer" && consumer_drains?(p, name) },
|
|
40
|
+
siblings: level ? priority_siblings(name, logical) : [], priority_level: level
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def pause_state_of(state)
|
|
47
|
+
return RUNNING unless state&.paused
|
|
48
|
+
|
|
49
|
+
{ paused: true, reason: state.paused_reason, paused_at: state.paused_at,
|
|
50
|
+
resumes_at: state.circuit_breaker_resume_at, trip_count: state.circuit_breaker_trip_count.to_i }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The level of a priority sub-table, or nil. `_pN` is legal in an
|
|
54
|
+
# ordinary queue name, so only a table the queue strategy creates for
|
|
55
|
+
# the stripped logical name counts.
|
|
56
|
+
def priority_level_of(table)
|
|
57
|
+
level = table[Pgbus::Web::QueueSummary::PRIORITY_LEVEL, 1]
|
|
58
|
+
return unless level && @client.physical_queue_names(logical_queue_name(table)).include?(table)
|
|
59
|
+
|
|
60
|
+
level.to_i
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
Pgbus.logger.debug { "[Pgbus::Web] Error resolving priority level of #{table}: #{e.class}: #{e.message}" }
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# [names of the capsules whose queues expand to this table, wildcard?].
|
|
67
|
+
# An anonymous capsule goes by its first queue. Fails open to a
|
|
68
|
+
# wildcard, like drained_queue_names: never a false "nothing drains it".
|
|
69
|
+
def draining_capsules(name)
|
|
70
|
+
capsules = Array(Pgbus.configuration.workers)
|
|
71
|
+
wildcard = capsules.any? { |c| capsule_queue_list(c).include?("*") }
|
|
72
|
+
names = capsules.filter_map do |c|
|
|
73
|
+
queues = capsule_queue_list(c) - ["*"]
|
|
74
|
+
next unless queues.any? { |q| @client.physical_queue_names(q).include?(name) }
|
|
75
|
+
|
|
76
|
+
(c[:name] || c["name"] || queues.first).to_s
|
|
77
|
+
end
|
|
78
|
+
[names, wildcard]
|
|
79
|
+
rescue StandardError => e
|
|
80
|
+
Pgbus.logger.error { "[Pgbus::Web] Error resolving capsules for #{name}: #{e.class}: #{e.message}" }
|
|
81
|
+
[[], true]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def capsule_queue_list(capsule)
|
|
85
|
+
Array(capsule[:queues] || capsule["queues"]).map(&:to_s)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# A heartbeat lists queue names as configured (Array or comma-separated
|
|
89
|
+
# String); tables are named after their normalized form ("bulk-imports"
|
|
90
|
+
# → pgbus_bulk_imports), so compare that.
|
|
91
|
+
def worker_drains?(process, logical)
|
|
92
|
+
queues = Array((process[:metadata] || {})["queues"]).flat_map { |q| q.to_s.split(",") }.map(&:strip)
|
|
93
|
+
queues.include?("*") || queues.any? { |q| normalized_queue(q) == logical }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# A consumer drains a handler queue when one of its topic filters
|
|
97
|
+
# overlaps a subscription routed to it (the rule the consumer itself
|
|
98
|
+
# uses to pick queues). A heartbeat without topics counts.
|
|
99
|
+
def consumer_drains?(process, name)
|
|
100
|
+
topics = Array((process[:metadata] || {})["topics"])
|
|
101
|
+
return true if topics.empty?
|
|
102
|
+
|
|
103
|
+
patterns = registered_subscribers.select { |s| s[:physical_queue_name] == name }.map { |s| s[:pattern] }
|
|
104
|
+
registry = EventBus::Registry.instance
|
|
105
|
+
topics.any? { |t| patterns.any? { |pattern| registry.pattern_overlaps?(t.to_s, pattern) } }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def normalized_queue(queue)
|
|
109
|
+
Pgbus.configuration.queue_name(queue).delete_prefix("#{Pgbus.configuration.queue_prefix}_")
|
|
110
|
+
rescue ArgumentError
|
|
111
|
+
queue
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def priority_siblings(name, logical)
|
|
115
|
+
queues_with_metrics.map { |q| q[:name] }.select do |n|
|
|
116
|
+
n != name && n.match?(Pgbus::Web::QueueSummary::PRIORITY_LEVEL) && logical_queue_name(n) == logical
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|