pgbus 0.9.5 → 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/Rakefile +56 -3
- data/app/controllers/pgbus/dead_letter_controller.rb +5 -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/queues/show.html.erb +3 -0
- data/config/locales/da.yml +7 -0
- data/config/locales/de.yml +7 -0
- data/config/locales/en.yml +7 -0
- data/config/locales/es.yml +7 -0
- data/config/locales/fi.yml +7 -0
- data/config/locales/fr.yml +7 -0
- data/config/locales/it.yml +7 -0
- data/config/locales/ja.yml +7 -0
- data/config/locales/nb.yml +7 -0
- data/config/locales/nl.yml +7 -0
- data/config/locales/pt.yml +7 -0
- data/config/locales/sv.yml +7 -0
- data/lib/pgbus/configuration.rb +1 -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/version.rb +1 -1
- data/lib/pgbus/web/data_source.rb +21 -0
- metadata +2 -1
|
@@ -1,65 +1,156 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
2
|
+
"metric_keys": [
|
|
3
|
+
"pgbus_stream_broadcast_count"
|
|
4
|
+
],
|
|
5
|
+
"dashboard": {
|
|
6
|
+
"title": "Pgbus — Streams",
|
|
7
|
+
"description": "Real-time SSE pub/sub. Broadcasts, fanout, active connections,\nand the outbox/recurring scheduler.\n",
|
|
8
|
+
"visuals": [
|
|
9
|
+
{
|
|
10
|
+
"type": "timeseries",
|
|
11
|
+
"display": "LINE",
|
|
12
|
+
"title": "Stream broadcasts per minute",
|
|
13
|
+
"line_label": "%stream% - %deferred%",
|
|
14
|
+
"format": "number",
|
|
15
|
+
"draw_null_as_zero": true,
|
|
16
|
+
"metrics": [
|
|
17
|
+
{
|
|
18
|
+
"name": "pgbus_stream_broadcast_count",
|
|
19
|
+
"fields": [
|
|
20
|
+
{
|
|
21
|
+
"field": "COUNTER"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"tags": [
|
|
25
|
+
{
|
|
26
|
+
"key": "stream",
|
|
27
|
+
"value": "*"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"key": "deferred",
|
|
31
|
+
"value": "*"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "timeseries",
|
|
39
|
+
"display": "LINE",
|
|
40
|
+
"title": "Active SSE connections",
|
|
41
|
+
"description": "Estimated from connect/disconnect events in the last 60 minutes.",
|
|
42
|
+
"line_label": "Active connections",
|
|
43
|
+
"format": "number",
|
|
44
|
+
"draw_null_as_zero": true,
|
|
45
|
+
"metrics": [
|
|
46
|
+
{
|
|
47
|
+
"name": "pgbus_stream_active_connections",
|
|
48
|
+
"fields": [
|
|
49
|
+
{
|
|
50
|
+
"field": "GAUGE"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"tags": []
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "timeseries",
|
|
59
|
+
"display": "LINE",
|
|
60
|
+
"title": "Average fanout per broadcast",
|
|
61
|
+
"description": "Mean number of connections that received each broadcast over the last hour.",
|
|
62
|
+
"line_label": "Avg fanout",
|
|
63
|
+
"format": "number",
|
|
64
|
+
"draw_null_as_zero": false,
|
|
65
|
+
"metrics": [
|
|
66
|
+
{
|
|
67
|
+
"name": "pgbus_stream_avg_fanout",
|
|
68
|
+
"fields": [
|
|
69
|
+
{
|
|
70
|
+
"field": "GAUGE"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"tags": []
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "timeseries",
|
|
79
|
+
"display": "LINE",
|
|
80
|
+
"title": "Broadcast payload size (bytes)",
|
|
81
|
+
"description": "Distribution of payload bytes. Use to spot accidentally-streaming-an-entire-page bugs.",
|
|
82
|
+
"line_label": "%stream%",
|
|
83
|
+
"format": "size",
|
|
84
|
+
"format_input": "byte",
|
|
85
|
+
"draw_null_as_zero": false,
|
|
86
|
+
"metrics": [
|
|
87
|
+
{
|
|
88
|
+
"name": "pgbus_stream_broadcast_bytes",
|
|
89
|
+
"fields": [
|
|
90
|
+
{
|
|
91
|
+
"field": "MEAN"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"field": "P95"
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"tags": [
|
|
98
|
+
{
|
|
99
|
+
"key": "stream",
|
|
100
|
+
"value": "*"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "timeseries",
|
|
108
|
+
"display": "LINE",
|
|
109
|
+
"title": "Outbox publishes per minute",
|
|
110
|
+
"line_label": "%kind%",
|
|
111
|
+
"format": "number",
|
|
112
|
+
"draw_null_as_zero": true,
|
|
113
|
+
"metrics": [
|
|
114
|
+
{
|
|
115
|
+
"name": "pgbus_outbox_published",
|
|
116
|
+
"fields": [
|
|
117
|
+
{
|
|
118
|
+
"field": "COUNTER"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"tags": [
|
|
122
|
+
{
|
|
123
|
+
"key": "kind",
|
|
124
|
+
"value": "*"
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"type": "timeseries",
|
|
132
|
+
"display": "LINE",
|
|
133
|
+
"title": "Recurring tasks enqueued per minute",
|
|
134
|
+
"line_label": "%task%",
|
|
135
|
+
"format": "number",
|
|
136
|
+
"draw_null_as_zero": true,
|
|
137
|
+
"metrics": [
|
|
138
|
+
{
|
|
139
|
+
"name": "pgbus_recurring_enqueued",
|
|
140
|
+
"fields": [
|
|
141
|
+
{
|
|
142
|
+
"field": "COUNTER"
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"tags": [
|
|
146
|
+
{
|
|
147
|
+
"key": "task",
|
|
148
|
+
"value": "*"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
65
156
|
}
|
|
@@ -1,81 +1,220 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
2
|
+
"metric_keys": [
|
|
3
|
+
"pgbus_queue_job_count",
|
|
4
|
+
"pgbus_event_count",
|
|
5
|
+
"pgbus_messages_sent",
|
|
6
|
+
"pgbus_messages_read"
|
|
7
|
+
],
|
|
8
|
+
"dashboard": {
|
|
9
|
+
"title": "Pgbus — Throughput & Latency",
|
|
10
|
+
"description": "Job and event throughput, perform-duration percentiles, and PGMQ send/read counts.\nDrives the most common 'is the worker keeping up?' question.\n",
|
|
11
|
+
"visuals": [
|
|
12
|
+
{
|
|
13
|
+
"type": "timeseries",
|
|
14
|
+
"display": "LINE",
|
|
15
|
+
"title": "Jobs processed per minute",
|
|
16
|
+
"description": "Successful, failed, and dead-lettered jobs. A spike in failed without a spike in processed usually means a deploy regression.",
|
|
17
|
+
"line_label": "%queue% - %job_class% - %status%",
|
|
18
|
+
"format": "number",
|
|
19
|
+
"draw_null_as_zero": true,
|
|
20
|
+
"metrics": [
|
|
21
|
+
{
|
|
22
|
+
"name": "pgbus_queue_job_count",
|
|
23
|
+
"fields": [
|
|
24
|
+
{
|
|
25
|
+
"field": "COUNTER"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"tags": [
|
|
29
|
+
{
|
|
30
|
+
"key": "queue",
|
|
31
|
+
"value": "*"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"key": "job_class",
|
|
35
|
+
"value": "*"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"key": "status",
|
|
39
|
+
"value": "*"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "timeseries",
|
|
47
|
+
"display": "LINE",
|
|
48
|
+
"title": "Job perform duration (ms)",
|
|
49
|
+
"description": "Distribution of how long perform_now takes per job class. P95 and P99 are the lines to watch.",
|
|
50
|
+
"line_label": "%job_class%",
|
|
51
|
+
"format": "duration",
|
|
52
|
+
"draw_null_as_zero": false,
|
|
53
|
+
"metrics": [
|
|
54
|
+
{
|
|
55
|
+
"name": "pgbus_job_duration_ms",
|
|
56
|
+
"fields": [
|
|
57
|
+
{
|
|
58
|
+
"field": "MEAN"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"field": "P95"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"field": "P99"
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"tags": [
|
|
68
|
+
{
|
|
69
|
+
"key": "job_class",
|
|
70
|
+
"value": "*"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "timeseries",
|
|
78
|
+
"display": "LINE",
|
|
79
|
+
"title": "Events processed per minute",
|
|
80
|
+
"description": "Event-bus handler invocations grouped by routing key.",
|
|
81
|
+
"line_label": "%routing_key% - %handler% - %status%",
|
|
82
|
+
"format": "number",
|
|
83
|
+
"draw_null_as_zero": true,
|
|
84
|
+
"metrics": [
|
|
85
|
+
{
|
|
86
|
+
"name": "pgbus_event_count",
|
|
87
|
+
"fields": [
|
|
88
|
+
{
|
|
89
|
+
"field": "COUNTER"
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"tags": [
|
|
93
|
+
{
|
|
94
|
+
"key": "routing_key",
|
|
95
|
+
"value": "*"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"key": "handler",
|
|
99
|
+
"value": "*"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"key": "status",
|
|
103
|
+
"value": "*"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "timeseries",
|
|
111
|
+
"display": "LINE",
|
|
112
|
+
"title": "Event handler duration (ms)",
|
|
113
|
+
"line_label": "%handler%",
|
|
114
|
+
"format": "duration",
|
|
115
|
+
"draw_null_as_zero": false,
|
|
116
|
+
"metrics": [
|
|
117
|
+
{
|
|
118
|
+
"name": "pgbus_event_duration_ms",
|
|
119
|
+
"fields": [
|
|
120
|
+
{
|
|
121
|
+
"field": "MEAN"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"field": "P95"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"field": "P99"
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"tags": [
|
|
131
|
+
{
|
|
132
|
+
"key": "handler",
|
|
133
|
+
"value": "*"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"type": "timeseries",
|
|
141
|
+
"display": "LINE",
|
|
142
|
+
"title": "PGMQ messages sent (per minute)",
|
|
143
|
+
"line_label": "%queue%",
|
|
144
|
+
"format": "number",
|
|
145
|
+
"draw_null_as_zero": true,
|
|
146
|
+
"metrics": [
|
|
147
|
+
{
|
|
148
|
+
"name": "pgbus_messages_sent",
|
|
149
|
+
"fields": [
|
|
150
|
+
{
|
|
151
|
+
"field": "COUNTER"
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
"tags": [
|
|
155
|
+
{
|
|
156
|
+
"key": "queue",
|
|
157
|
+
"value": "*"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"type": "timeseries",
|
|
165
|
+
"display": "LINE",
|
|
166
|
+
"title": "Send duration (ms)",
|
|
167
|
+
"line_label": "%queue%",
|
|
168
|
+
"format": "duration",
|
|
169
|
+
"draw_null_as_zero": false,
|
|
170
|
+
"metrics": [
|
|
171
|
+
{
|
|
172
|
+
"name": "pgbus_send_duration_ms",
|
|
173
|
+
"fields": [
|
|
174
|
+
{
|
|
175
|
+
"field": "MEAN"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"field": "P95"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"field": "P99"
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"tags": [
|
|
185
|
+
{
|
|
186
|
+
"key": "queue",
|
|
187
|
+
"value": "*"
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"type": "timeseries",
|
|
195
|
+
"display": "LINE",
|
|
196
|
+
"title": "PGMQ messages read (per minute)",
|
|
197
|
+
"description": "Messages fetched from queues by workers. Compare against 'sent' to spot backlog growth.",
|
|
198
|
+
"line_label": "%queue%",
|
|
199
|
+
"format": "number",
|
|
200
|
+
"draw_null_as_zero": true,
|
|
201
|
+
"metrics": [
|
|
202
|
+
{
|
|
203
|
+
"name": "pgbus_messages_read",
|
|
204
|
+
"fields": [
|
|
205
|
+
{
|
|
206
|
+
"field": "COUNTER"
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
"tags": [
|
|
210
|
+
{
|
|
211
|
+
"key": "queue",
|
|
212
|
+
"value": "*"
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
}
|
|
81
220
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "socket"
|
|
4
|
+
|
|
3
5
|
module Pgbus
|
|
4
6
|
module Integrations
|
|
5
7
|
module Appsignal
|
|
@@ -10,6 +12,14 @@ module Pgbus
|
|
|
10
12
|
# method rescues StandardError and returns a safe default — but we
|
|
11
13
|
# still wrap each section in our own rescue so a probe iteration
|
|
12
14
|
# never raises out into the AppSignal probe runner.
|
|
15
|
+
#
|
|
16
|
+
# Tagging policy: most pgbus metrics are cluster-wide (the queue
|
|
17
|
+
# depth in PostgreSQL is the same regardless of which host reads it),
|
|
18
|
+
# so cluster-wide gauges are emitted WITHOUT a hostname tag — every
|
|
19
|
+
# host sends the same value and AppSignal's last-write-wins
|
|
20
|
+
# semantics keep the dashboard correct. The only gauge that is
|
|
21
|
+
# genuinely per-host is `active_processes`, which the probe filters
|
|
22
|
+
# to this host before tagging.
|
|
13
23
|
module Probe
|
|
14
24
|
METRIC_PREFIX = "pgbus_"
|
|
15
25
|
private_constant :METRIC_PREFIX
|
|
@@ -43,6 +53,7 @@ module Pgbus
|
|
|
43
53
|
class Runner
|
|
44
54
|
def initialize(data_source: nil)
|
|
45
55
|
@data_source = data_source
|
|
56
|
+
@hostname = Socket.gethostname
|
|
46
57
|
end
|
|
47
58
|
|
|
48
59
|
def call
|
|
@@ -68,14 +79,18 @@ module Pgbus
|
|
|
68
79
|
gauge "queue_visible_depth", q[:queue_visible_length], tags
|
|
69
80
|
gauge "queue_paused", q[:paused] ? 1 : 0, tags
|
|
70
81
|
age = q[:oldest_msg_age_sec]
|
|
71
|
-
|
|
82
|
+
if age
|
|
83
|
+
gauge "queue_oldest_message_age_seconds", age, tags
|
|
84
|
+
gauge "queue_latency", age * 1_000, tags
|
|
85
|
+
end
|
|
72
86
|
end
|
|
73
87
|
rescue StandardError => e
|
|
74
88
|
log_failure("queue metrics", e)
|
|
75
89
|
end
|
|
76
90
|
|
|
77
91
|
def track_processes
|
|
78
|
-
|
|
92
|
+
local_count = data_source.processes.count { |p| p[:hostname] == @hostname }
|
|
93
|
+
gauge "active_processes", local_count, { hostname: @hostname }
|
|
79
94
|
rescue StandardError => e
|
|
80
95
|
log_failure("process metrics", e)
|
|
81
96
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "json"
|
|
3
4
|
require "pgbus/integrations/appsignal/subscriber"
|
|
4
5
|
require "pgbus/integrations/appsignal/probe"
|
|
5
6
|
|
|
@@ -24,6 +25,9 @@ module Pgbus
|
|
|
24
25
|
# All metric names are prefixed `pgbus_` so they group cleanly in
|
|
25
26
|
# AppSignal's custom-metrics view.
|
|
26
27
|
module Appsignal
|
|
28
|
+
DASHBOARD_PATH = File.expand_path("appsignal/dashboard.json", __dir__).freeze
|
|
29
|
+
DASHBOARDS_DIR = File.expand_path("appsignal/dashboards", __dir__).freeze
|
|
30
|
+
|
|
27
31
|
module_function
|
|
28
32
|
|
|
29
33
|
def install! # rubocop:disable Naming/PredicateMethod
|
|
@@ -41,11 +45,24 @@ module Pgbus
|
|
|
41
45
|
@installed == true
|
|
42
46
|
end
|
|
43
47
|
|
|
48
|
+
def dashboard_definition
|
|
49
|
+
@dashboard_definition ||= JSON.parse(File.read(DASHBOARD_PATH))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def dashboard_definitions
|
|
53
|
+
@dashboard_definitions ||=
|
|
54
|
+
Dir[File.join(DASHBOARDS_DIR, "*.json")].map do |path|
|
|
55
|
+
JSON.parse(File.read(path))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
44
59
|
# Test hook: tear everything down so a fresh install! can run.
|
|
45
60
|
def reset!
|
|
46
61
|
Subscriber.reset! if defined?(Subscriber)
|
|
47
62
|
Probe.reset! if defined?(Probe)
|
|
48
63
|
@installed = false
|
|
64
|
+
@dashboard_definition = nil
|
|
65
|
+
@dashboard_definitions = nil
|
|
49
66
|
end
|
|
50
67
|
end
|
|
51
68
|
end
|
data/lib/pgbus/version.rb
CHANGED
|
@@ -41,7 +41,17 @@ module Pgbus
|
|
|
41
41
|
# Queues — query via ActiveRecord for reliability in web processes
|
|
42
42
|
# (avoids PGMQ client connection issues when the web server uses a
|
|
43
43
|
# different connection lifecycle than the worker processes).
|
|
44
|
+
# Memoized for the lifetime of this data-source instance (one per web
|
|
45
|
+
# request — see ApplicationController#data_source). A single page can ask
|
|
46
|
+
# for queue metrics more than once (e.g. the DLQ page reads both the
|
|
47
|
+
# message rows and the total count); without the memo each call re-runs
|
|
48
|
+
# the meta query + batched metrics. Mutations redirect to a fresh request
|
|
49
|
+
# with a new instance, so a per-request memo never serves stale data.
|
|
44
50
|
def queues_with_metrics
|
|
51
|
+
@queues_with_metrics ||= fetch_queues_with_metrics
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def fetch_queues_with_metrics
|
|
45
55
|
queue_names = connection.select_values("SELECT queue_name FROM pgmq.meta ORDER BY queue_name")
|
|
46
56
|
return [] if queue_names.empty?
|
|
47
57
|
|
|
@@ -53,6 +63,7 @@ module Pgbus
|
|
|
53
63
|
Pgbus.logger.error { "[Pgbus::Web] Error fetching queue metrics: #{e.class}: #{e.message}" }
|
|
54
64
|
[]
|
|
55
65
|
end
|
|
66
|
+
private :fetch_queues_with_metrics
|
|
56
67
|
|
|
57
68
|
# name is the full PGMQ queue name (e.g. "pgbus_default") as returned
|
|
58
69
|
# by queues_with_metrics. No prefix is added.
|
|
@@ -276,6 +287,16 @@ module Pgbus
|
|
|
276
287
|
[]
|
|
277
288
|
end
|
|
278
289
|
|
|
290
|
+
def dlq_total_count
|
|
291
|
+
dlq_suffix = Pgbus::DEAD_LETTER_SUFFIX
|
|
292
|
+
queues_with_metrics
|
|
293
|
+
.select { |q| q[:name].end_with?(dlq_suffix) }
|
|
294
|
+
.sum { |q| q[:queue_length] }
|
|
295
|
+
rescue StandardError => e
|
|
296
|
+
Pgbus.logger.debug { "[Pgbus::Web] Error fetching DLQ count: #{e.message}" }
|
|
297
|
+
0
|
|
298
|
+
end
|
|
299
|
+
|
|
279
300
|
def dlq_message_detail(msg_id)
|
|
280
301
|
dlq_suffix = Pgbus::DEAD_LETTER_SUFFIX
|
|
281
302
|
queues = queues_with_metrics.select { |q| q[:name].end_with?(dlq_suffix) }
|