Skip to content

Commit 0d98228

Browse files
committed
Make metrics server asyncio
Get server functional Finish config, get test done Reduce initial metrics we are reporting Update the README Try and fix mypy check Fix integration tests because coverage was added Add test dep Update schema again Use conditional import to protect users without extras installed
1 parent 601d1d6 commit 0d98228

File tree

10 files changed

+210
-257
lines changed

10 files changed

+210
-257
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ jobs:
2424
python-version: ${{ matrix.py_version }}
2525

2626
- name: Install dispatcherd
27-
run: pip install -e .[pg_notify]
27+
run: pip install -e .[pg_notify,metrics]
2828
- run: make postgres
29-
- run: pip install pytest pytest-asyncio
29+
- run: pip install pytest pytest-asyncio httpx
3030
- run: pytest tests/unit tests/integration -vv -s
3131

3232
black:
@@ -60,7 +60,7 @@ jobs:
6060
show-progress: false
6161

6262
- run: pip install mypy
63-
- run: pip install -e .[pg_notify]
63+
- run: pip install -e .[pg_notify,metrics]
6464
- run: python3 -m pip install types-PyYAML
6565
- run: mypy dispatcherd
6666

README.md

Lines changed: 19 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -235,144 +235,32 @@ Dispatcherd is sponsored by [Red Hat, Inc](https://www.redhat.com).
235235

236236
## Metrics
237237

238-
Start the dispatcher.
238+
You can run a demo of the metrics server. In your first terminal tab, run:
239239

240240
```
241-
pip install prometheus_client
241+
pip install .[pg_notify,metrics]
242+
dispatcherd
243+
```
242244

243-
$ curl http://localhost:8070
245+
In another tab run:
244246

247+
```
245248
curl http://localhost:8070
249+
```
250+
251+
This should report metrics in the following general format:
252+
253+
```
254+
$ curl http://localhost:8070
246255
# HELP dispatcher_messages_received_total Number of messages received by dispatchermain
247256
# TYPE dispatcher_messages_received_total counter
248-
dispatcher_messages_received_total 88.0
257+
dispatcher_messages_received_total 263.0
249258
# HELP dispatcher_control_messages_count_total Number of control messages received.
250259
# TYPE dispatcher_control_messages_count_total counter
251-
dispatcher_control_messages_count_total 10.0
252-
# HELP dispatcher_worker_created_at Creation time of worker
253-
# TYPE dispatcher_worker_created_at gauge
254-
dispatcher_worker_created_at{worker_index="0"} 286576.365272104
255-
dispatcher_worker_created_at{worker_index="1"} 286576.365368035
256-
dispatcher_worker_created_at{worker_index="2"} 286578.814706941
257-
dispatcher_worker_created_at{worker_index="3"} 286578.817639637
258-
dispatcher_worker_created_at{worker_index="4"} 286578.820265243
259-
dispatcher_worker_created_at{worker_index="5"} 286578.822075874
260-
dispatcher_worker_created_at{worker_index="6"} 286578.824725725
261-
dispatcher_worker_created_at{worker_index="7"} 286578.837810563
262-
dispatcher_worker_created_at{worker_index="8"} 286578.844329095
263-
dispatcher_worker_created_at{worker_index="9"} 286578.863277972
264-
dispatcher_worker_created_at{worker_index="10"} 286578.878555905
265-
dispatcher_worker_created_at{worker_index="11"} 286579.36656921
266-
# HELP dispatcher_worker_finished_count Finished count of tasks by the worker
267-
# TYPE dispatcher_worker_finished_count gauge
268-
dispatcher_worker_finished_count{worker_index="0"} 2.0
269-
dispatcher_worker_finished_count{worker_index="1"} 1.0
270-
dispatcher_worker_finished_count{worker_index="2"} 1.0
271-
dispatcher_worker_finished_count{worker_index="3"} 7.0
272-
dispatcher_worker_finished_count{worker_index="4"} 8.0
273-
dispatcher_worker_finished_count{worker_index="5"} 1.0
274-
dispatcher_worker_finished_count{worker_index="6"} 0.0
275-
dispatcher_worker_finished_count{worker_index="7"} 0.0
276-
dispatcher_worker_finished_count{worker_index="8"} 0.0
277-
dispatcher_worker_finished_count{worker_index="9"} 2.0
278-
dispatcher_worker_finished_count{worker_index="10"} 1.0
279-
dispatcher_worker_finished_count{worker_index="11"} 1.0
280-
# HELP dispatcher_worker_status Status of worker.
281-
# TYPE dispatcher_worker_status gauge
282-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="0"} 0.0
283-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="0"} 0.0
284-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="0"} 0.0
285-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="0"} 1.0
286-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="0"} 0.0
287-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="0"} 0.0
288-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="0"} 0.0
289-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="0"} 0.0
290-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="1"} 0.0
291-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="1"} 0.0
292-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="1"} 0.0
293-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="1"} 1.0
294-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="1"} 0.0
295-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="1"} 0.0
296-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="1"} 0.0
297-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="1"} 0.0
298-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="2"} 0.0
299-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="2"} 0.0
300-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="2"} 0.0
301-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="2"} 1.0
302-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="2"} 0.0
303-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="2"} 0.0
304-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="2"} 0.0
305-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="2"} 0.0
306-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="3"} 0.0
307-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="3"} 0.0
308-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="3"} 0.0
309-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="3"} 1.0
310-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="3"} 0.0
311-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="3"} 0.0
312-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="3"} 0.0
313-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="3"} 0.0
314-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="4"} 0.0
315-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="4"} 0.0
316-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="4"} 0.0
317-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="4"} 1.0
318-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="4"} 0.0
319-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="4"} 0.0
320-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="4"} 0.0
321-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="4"} 0.0
322-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="5"} 0.0
323-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="5"} 0.0
324-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="5"} 0.0
325-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="5"} 1.0
326-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="5"} 0.0
327-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="5"} 0.0
328-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="5"} 0.0
329-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="5"} 0.0
330-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="6"} 0.0
331-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="6"} 0.0
332-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="6"} 0.0
333-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="6"} 1.0
334-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="6"} 0.0
335-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="6"} 0.0
336-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="6"} 0.0
337-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="6"} 0.0
338-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="7"} 0.0
339-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="7"} 0.0
340-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="7"} 0.0
341-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="7"} 1.0
342-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="7"} 0.0
343-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="7"} 0.0
344-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="7"} 0.0
345-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="7"} 0.0
346-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="8"} 0.0
347-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="8"} 0.0
348-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="8"} 0.0
349-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="8"} 1.0
350-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="8"} 0.0
351-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="8"} 0.0
352-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="8"} 0.0
353-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="8"} 0.0
354-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="9"} 0.0
355-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="9"} 0.0
356-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="9"} 0.0
357-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="9"} 1.0
358-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="9"} 0.0
359-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="9"} 0.0
360-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="9"} 0.0
361-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="9"} 0.0
362-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="10"} 0.0
363-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="10"} 0.0
364-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="10"} 0.0
365-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="10"} 1.0
366-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="10"} 0.0
367-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="10"} 0.0
368-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="10"} 0.0
369-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="10"} 0.0
370-
dispatcher_worker_status{dispatcher_worker_status="error",worker_index="11"} 0.0
371-
dispatcher_worker_status{dispatcher_worker_status="exited",worker_index="11"} 0.0
372-
dispatcher_worker_status{dispatcher_worker_status="initialized",worker_index="11"} 0.0
373-
dispatcher_worker_status{dispatcher_worker_status="ready",worker_index="11"} 1.0
374-
dispatcher_worker_status{dispatcher_worker_status="retired",worker_index="11"} 0.0
375-
dispatcher_worker_status{dispatcher_worker_status="spawned",worker_index="11"} 0.0
376-
dispatcher_worker_status{dispatcher_worker_status="starting",worker_index="11"} 0.0
377-
dispatcher_worker_status{dispatcher_worker_status="stopping",worker_index="11"} 0.0
260+
dispatcher_control_messages_count_total 0.0
261+
# HELP dispatcher_worker_count_total Number of workers running.
262+
# TYPE dispatcher_worker_count_total counter
263+
dispatcher_worker_count_total 3.0
378264
```
265+
266+
We expect to add more metrics in the future.

dispatcher.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ service:
88
scaledown_wait: 15 # seconds
99
main_kwargs:
1010
node_id: demo-server-a
11+
metrics_kwargs:
12+
log_level: debug
1113
brokers:
1214
pg_notify:
1315
config:

dispatcherd/factories.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ def from_settings(settings: LazySettings = global_settings) -> DispatcherMain:
6262
producers = producers_from_settings(settings=settings)
6363
pool = pool_from_settings(settings=settings)
6464
extra_kwargs = settings.service.get('main_kwargs', {})
65+
66+
metrics_kwargs = settings.service.get('metrics_kwargs')
67+
if metrics_kwargs:
68+
from .service.metrics import DispatcherMetricsServer
69+
70+
extra_kwargs['metrics'] = DispatcherMetricsServer(**metrics_kwargs)
71+
6572
return DispatcherMain(producers, pool, **extra_kwargs)
6673

6774

@@ -105,7 +112,7 @@ def get_control_from_settings(publish_broker: Optional[str] = None, settings: La
105112

106113
# ---- Schema generation ----
107114

108-
SERIALIZED_TYPES = (int, str, dict, type(None), tuple, list, float)
115+
SERIALIZED_TYPES = (int, str, dict, type(None), tuple, list, float, bool)
109116

110117

111118
def is_valid_annotation(annotation):
@@ -134,6 +141,9 @@ def generate_settings_schema(settings: LazySettings = global_settings) -> dict:
134141

135142
ret['service']['pool_kwargs'] = schema_for_cls(WorkerPool)
136143
ret['service']['main_kwargs'] = schema_for_cls(DispatcherMain)
144+
from .service.metrics import DispatcherMetricsServer
145+
146+
ret['service']['metrics_kwargs'] = schema_for_cls(DispatcherMetricsServer)
137147
ret['service']['process_manager_kwargs'] = {}
138148
pm_classes = (process.ProcessManager, process.ForkServerManager)
139149
for pm_cls in pm_classes:

dispatcherd/protocols.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,17 @@ def get_status_data(self) -> dict:
193193
async def shutdown(self) -> None: ...
194194

195195

196+
class DispatcherMetricsServer(Protocol):
197+
"""
198+
Metrics object will be created by factories.
199+
200+
If the extra is not installed, we may not have needed python dependencies.
201+
This only needs to capture the interace of the initialized object with DispatcherMain.
202+
"""
203+
204+
async def start_server(self, dispatcher: 'DispatcherMain') -> None: ...
205+
206+
196207
class DispatcherMain(Protocol):
197208
"""
198209
Describes the primary dispatcherd interface.
@@ -207,6 +218,9 @@ class DispatcherMain(Protocol):
207218
fd_lock: asyncio.Lock # Forking and locking may need to be serialized, which this does
208219
producers: Iterable[Producer]
209220

221+
received_count: int
222+
control_count: int
223+
210224
async def main(self) -> None:
211225
"""This is the method that runs the service, bring your own event loop"""
212226
...

0 commit comments

Comments
 (0)