Skip to content

Reduce memory use of the waiting_tasks metric - #8009

Merged
gerrod3 merged 2 commits into
pulp:mainfrom
aKlimau:tasks-in-memory
Sep 15, 2026
Merged

gerrod3 merged 2 commits into
pulp:mainfrom
aKlimau:tasks-in-memory

Conversation

@aKlimau

@aKlimau aKlimau commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

count_waiting_tasks_for_metric() now streams reserved_resources_record via values_list().iterator() instead of materializing deferred Task instances.

The "shared:" split is moved into redis_locks._split_reserved_resources().

ref #7986

📜 Checklist

  • Commits are cleanly separated with meaningful messages (simple features and bug fixes should be squashed to one commit)
  • A changelog entry or entries has been added for any significant changes
  • Follows the Pulp policy on AI Usage
  • (For new features) - User documentation and test coverage has been added

See: Pull Request Walkthrough

@aKlimau aKlimau changed the title Reduce memory use of the waiting_tasks metric Reduce memory use of the waiting_tasks metric #7986 Aug 25, 2026
@aKlimau aKlimau changed the title Reduce memory use of the waiting_tasks metric #7986 Reduce memory use of the waiting_tasks metric Aug 25, 2026
@aKlimau

aKlimau commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

After discussing all the suggested solutions in #7986 with claude, it looks like solutions 2 and 3 would have a positive impact on memory usage with no behavioral change.

METRIC_HEARTBEAT_INTERVAL is a separate change that would make metrics not as fresh, so we'd need to decide weather it's worth.

And using Redis cache doesn't save us much, since the computation is always done by a single worker and runs once per cycle. So introducing a round trip and another potential point of failure doesn't seem worth it to me.

@aKlimau

aKlimau commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@decko by any chance do we have a way to measure the performance impact of such changes? (Memory allocation during count_waiting_tasks_for_metric() call)

Comment thread pulpcore/tasking/redis_locks.py Outdated
"""
Split a ``reserved_resources_record`` array into (exclusive, shared) resource names.

Shared reservations are stored with a ``"shared:"`` prefix; exclusive ones are bare.

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.

Get rid of the double backticks please

The metric scans every waiting/running task but only needs each task's
reserved resources. Fetch just those instead of building a model object
per row.

ref pulp#7986

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread pulpcore/tasking/redis_worker.py Outdated
)
.order_by("pulp_created")
.only("reserved_resources_record")
.values_list("reserved_resources_record", flat=True) # Avoids Task object allocation

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.

The comment is not needed. Everyone working on the codebase is expected to know how django and values_list works.

Comment thread pulpcore/tasking/redis_locks.py Outdated
Comment on lines +436 to +439

Shared reservations are stored with a `"shared:"` prefix; exclusive ones are bare.
The prefix is stripped from the returned shared names.

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.

Suggested change
Shared reservations are stored with a `"shared:"` prefix; exclusive ones are bare.
The prefix is stripped from the returned shared names.

The code is pretty straightforward, not sure we need a comment describing it.

Comment thread CHANGES/7986.misc
@@ -0,0 +1 @@
Reduced the memory overhead of the Redis worker `waiting_tasks` metric by streaming reserved-resource records instead of loading full `Task` objects.

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.

I would mark this as a misc. It's not really a feature and we can backport if need be.

@decko

decko commented Sep 1, 2026

Copy link
Copy Markdown
Member

@decko by any chance do we have a way to measure the performance impact of such changes? (Memory allocation during count_waiting_tasks_for_metric() call)

We do have an opentelemetry profile on oci-env. It starts the opentelemetry-collector, Prometheus and Grafana. You could try to use it and check the worker memory consumption.

@aKlimau

aKlimau commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Benchmarked this before/after to check it's actually worth the change.

Ran both implementations back to back in one process against the same seeded tasks in a dev env. Best of 3 for time, separate pass for peak memory. Both implementations return identical counts.

tasks distinct resources old new old peak new peak
1,000 50 23 ms 4 ms 2.3 MB 0.3 MB
10,000 50 275 ms 19 ms 22.9 MB 1.2 MB
10,000 10,000 272 ms 23 ms 22.9 MB 2.1 MB
50,000 50 1991 ms 304 ms 114.5 MB 1.2 MB

6-14x faster, and peak memory goes from linear in queue depth to flat. Distinct resource count doesn't matter - 10k tasks over 50 resources and over 10k resources come out about the same.

@gerrod3
gerrod3 merged commit 3843a07 into pulp:main Sep 15, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants