Skip to content

[ADD] monitoring_prometheus_queue_job - #529

Open
gurneyalex wants to merge 1 commit into
14.0from
14.0-monitoring_prometheus_queuejob
Open

gurneyalex wants to merge 1 commit into
14.0from
14.0-monitoring_prometheus_queuejob

Conversation

@gurneyalex

Copy link
Copy Markdown
Member

This commit features a refactoring of monitoring_prometheus to get a cron gathering some metrics from the database, and then publishing the result on the /metrics endpoint

The new module monitoring_prometheus_queue_job extends the cron to get information about the queue job states.

@gurneyalex
gurneyalex force-pushed the 14.0-monitoring_prometheus_queuejob branch from 062eebf to 33bfbfe Compare September 3, 2026 13:59

@twalter-c2c twalter-c2c left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, AFAICT. Pre-commit needs to be satisfied. I dropped a few tiny comments, but they are not relevant to the code logic. Pre-approving.

"version": "14.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "category",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a more accurate category name? 😉

Comment thread monitoring_prometheus_queue_job/__manifest__.py Outdated
@@ -0,0 +1,42 @@
# Copyright 2016-2021 Camptocamp SA

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright 2016-2021 Camptocamp SA
# Copyright 2026 Camptocamp SA

Comment thread monitoring_prometheus/models/prometheus_gatherer.py
"""Collect application metrics to be exposed on the /metrics endpoint.

Metrics are gathered by a cron and stored as JSON in an
``ir.config_parameter``, because crons and HTTP workers run in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is interesting, but there's no better choice to store metrics, than ir.config_parameter?

I was just curious if it is a pattern used elsewhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can materialize a model for this. The main thing is that the value is gathered in one worker (the cron) and served over http, so we need to store it somewhere, we cannot keep it in memory (which is what is done for the http metrics in the module (which are useless btw, but this is a different issue). I also wanted to avoid having the /metrics endpoint make potentially complex SQL queries, to keep it fast.

I chose ir.config_parameter because it is guaranteed to be present and kind of "made sense" . What I did not check is if there is a cache invalidation involved when we update it (we certainly don't want that) -> will double check.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible alternatives could be:

  • ir.logging which is not used much
  • an attachment on ir.cron record with id "monitoring_prometheus.cron_prometheus_gather_metrics"

It could be a singleton record with an "external ID" to retrieve it with env.ref("monitoring_prometheus.metrics") for example and you're done.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a prometheus.metric model

@SilvioC2C SilvioC2C left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM; wondering if there's a better alternative to storing log values in a sys param (especially cause they can be edited manually from the UI), but definitely not a blocker

@divad1196 divad1196 left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR:

  • I don't see the benefit of the cron over doing the request on-the-fly when /metrics is called. We can simply configure prometheus to pull only every 15min
  • If there is a reason for it, I would prefer to use a prometheus collector and push to it from the cron instead.

return []

@api.model
def _cron_gather_metrics(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the cron

I don't really see the benefit of using a cron here.
If prometheus pull faster than the cron, it will store the same value over and over.

If there is a reason for that, maybe we should use a collector in push mode.
For example Prometheus Pushgateway or OpenTelemetry collector:

  • The cron push data directly to it
  • Prometheus collect from the collector

Prometheus itself accepts push, but it's usually preferable to keep it in pull mode.
This would at least offload Odoo and also avoid the ir.config_parameter trick.

The /metrics route only makes sense if we serve fresh data IMO.

Naming

It's a bit confusing here:
We also have _gather_queue_job_metrics, similar name, that actually extend _gather_metrics

This method should maybe be called _cron_persist_metrics

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a cron and storing the values means that they are collected once and for all, because these values are shared by all the workers which are part of the instance. I was concerned about hitting the database too hard with 15 pods being queried at the same time by prometheus on some instances. Maybe it is not an issue.

refactored the code for the naming.

_GAUGES = {}


def _get_gauge(name, documentation, label_names):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could mention that it's a multiton pattern.
This helps scanning the intent.

Alternative approach:

registry = CollectorRegistry()
for m in ... : 
     Gauge(m["name"], ... , registry=reg)

The key must be unique per registry, and when not specified, Gauge uses the global default registry.
To use it, I would group the data by metric name.

Benefit

Avoiding race condition and side effects

This is technically not and issue in worker mode as it currently process 1 request at the time, but this is an issue in thread mode. And this will be an issue with the hybrid mode.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check this later, unless you beat me to it and propose a PR (I will be away next week, I'm not sure of the importance of this for @florentx 's project

Comment thread monitoring_prometheus/controllers/prometheus_metrics.py Outdated
gauge = _get_gauge(name, metric.get("documentation", ""), sorted(labels))
if name not in cleared:
# drop the series that disappeared since the last collection
gauge.clear()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a metric is missing, it won't be cleared.
This is an issue in a multi-database server:
Metrics available on database A but not on B will still appear on B and not be cleared up.

We should have the clearup at the start, this would also remove the need for the set:

for g in _GAUGES.values():
    g.clear()

Using a new CollectorRegistry per request solves the issue

@sbidoul

sbidoul commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

@gurneyalex OCA/queue#976 may be of interest to you

@gurneyalex
gurneyalex force-pushed the 14.0-monitoring_prometheus_queuejob branch 3 times, most recently from 3ddc9e8 to 83405f8 Compare September 18, 2026 13:23
This commit features a refactoring of monitoring_prometheus to get a
cron gathering some metrics from the database, and then publishing the
result on the /metrics endpoint

The new module monitoring_prometheus_queue_job extends the cron to get
information about the queue job states.
@gurneyalex
gurneyalex force-pushed the 14.0-monitoring_prometheus_queuejob branch 2 times, most recently from 9b01c0e to 12d19ee Compare September 20, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants