From 81317e029fdbd89368f74801eaae0bac4239cf96 Mon Sep 17 00:00:00 2001 From: Larry Rios Date: Wed, 28 Oct 2026 13:04:05 -0400 Subject: [PATCH 1/2] Annotate the content membership experiment SQL with the repository (PULP-1996) Add a second comment, `/* repo= */`, after each variant's `pexp=... v=A|B` marker in patch 0081, so RDS Performance Insights shows both the variant and the target repository. The existing marker is unchanged, so the experiment collector's pattern and the existing test assertions still match. Use self.repository_id, which is already on the RepositoryVersion, to avoid a database fetch of the repository on every call. Add a test assertion for the repo comment. Co-Authored-By: Claude Sonnet 5.5 --- ...81-Experiment-interval-content-query.patch | 20 ++++++++++++------- .../unit/test_interval_content_experiment.py | 4 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/images/assets/patches/0081-Experiment-interval-content-query.patch b/images/assets/patches/0081-Experiment-interval-content-query.patch index abe72ff0..3d15685a 100644 --- a/images/assets/patches/0081-Experiment-interval-content-query.patch +++ b/images/assets/patches/0081-Experiment-interval-content-query.patch @@ -1,6 +1,6 @@ --- a/pulpcore/app/models/repository.py +++ b/pulpcore/app/models/repository.py -@@ -31,6 +31,7 @@ from pulpcore.cache import Cache +@@ -31,6 +31,7 @@ from pulpcore.constants import ALL_KNOWN_CONTENT_CHECKSUMS, PROTECTED_REPO_VERSION_MESSAGE from pulpcore.download.factory import DownloaderFactory from pulpcore.exceptions import ContentOverwriteError, ResourceImmutableError @@ -8,7 +8,7 @@ from .base import BaseModel, MasterModel from .content import Artifact, Content, ContentArtifact, RemoteArtifact -@@ -1029,7 +1030,16 @@ class RepositoryVersion(BaseModel): +@@ -1064,7 +1065,16 @@ if content_qs is None: content_qs = Content.objects @@ -26,7 +26,7 @@ def content_ids_subquery(self): """ -@@ -1044,10 +1054,43 @@ class RepositoryVersion(BaseModel): +@@ -1079,10 +1089,49 @@ """ return ( RepositoryVersion.objects.filter(pk=self.pk) @@ -35,8 +35,11 @@ + cids=Func( + F("content_ids"), + function="unnest", -+ # Marker so variant A is identifiable in RDS Performance Insights Top SQL -+ template="unnest(%(expressions)s) /* pexp=PULP-1996-CONTENT-MEMBERSHIP v=A */", ++ # Variant A and target repo markers, read from RDS Performance Insights ++ template=( ++ "unnest(%(expressions)s) /* pexp=PULP-1996-CONTENT-MEMBERSHIP v=A */" ++ f" /* repo={self.repository_id} */" ++ ), + ) + ) .values_list("cids", flat=True) @@ -61,8 +64,11 @@ + .annotate( + cid=Func( + F("content_id"), -+ # Marker so variant B is identifiable in RDS Performance Insights Top SQL -+ template="%(expressions)s /* pexp=PULP-1996-CONTENT-MEMBERSHIP v=B */", ++ # Variant B and target repo markers, read from RDS Performance Insights ++ template=( ++ "%(expressions)s /* pexp=PULP-1996-CONTENT-MEMBERSHIP v=B */" ++ f" /* repo={self.repository_id} */" ++ ), + ) + ) + .values_list("cid", flat=True) diff --git a/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py b/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py index d51aae27..4e3810b7 100644 --- a/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py +++ b/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py @@ -130,7 +130,7 @@ def test_get_content_experiment_dispatch(repository, content_pks, add_content, m def test_get_content_marks_sql_per_variant(repository, content_pks, add_content, monkeypatch): # noqa: ARG001 - """Both variants must reach the database with their RDS Performance Insights marker.""" + """Both variants reach the database with their variant and repository markers.""" with repository.new_version() as version: add_content(version, (1, 1, 1, 1, 1)) @@ -139,3 +139,5 @@ def test_get_content_marks_sql_per_variant(repository, content_pks, add_content, with CaptureQueriesContext(connection) as ctx: assert list(version.get_content()) assert any(marker in query["sql"] for query in ctx.captured_queries), marker + repo_marker = f"/* repo={repository.pk} */" + assert any(repo_marker in query["sql"] for query in ctx.captured_queries), repo_marker From f558b2deadff87a957ca1debe715e45dd2fc5045 Mon Sep 17 00:00:00 2001 From: Larry Rios Date: Wed, 28 Oct 2026 13:16:07 -0400 Subject: [PATCH 2/2] Add repository_id to the experiment dispatch log line (PULP-1996) Log the target repository on each ab_experiment_dispatch line, so CloudWatch counts can be split by repository, alongside the SQL annotation for RDS Performance Insights. run_lazy_experiment() takes an optional repository_id (null when not passed), and the get_content() call in patch 0081 passes self.repository_id. Add a test assertion for the field. Co-Authored-By: Claude Sonnet 5.5 --- .../patches/0081-Experiment-interval-content-query.patch | 5 +++-- pulp_service/pulp_service/app/experiments.py | 6 ++++-- .../tests/unit/test_interval_content_experiment.py | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/images/assets/patches/0081-Experiment-interval-content-query.patch b/images/assets/patches/0081-Experiment-interval-content-query.patch index 3d15685a..b1153c35 100644 --- a/images/assets/patches/0081-Experiment-interval-content-query.patch +++ b/images/assets/patches/0081-Experiment-interval-content-query.patch @@ -8,7 +8,7 @@ from .base import BaseModel, MasterModel from .content import Artifact, Content, ContentArtifact, RemoteArtifact -@@ -1064,7 +1065,16 @@ +@@ -1064,7 +1065,17 @@ if content_qs is None: content_qs = Content.objects @@ -22,11 +22,12 @@ + "PULP-1996-CONTENT-MEMBERSHIP", + control=lambda: content_qs.filter(pk__in=self.content_ids_subquery()), + candidate=lambda: content_qs.filter(pk__in=self.content_pks_subquery()), ++ repository_id=self.repository_id, + ) def content_ids_subquery(self): """ -@@ -1079,10 +1089,49 @@ +@@ -1079,10 +1090,49 @@ """ return ( RepositoryVersion.objects.filter(pk=self.pk) diff --git a/pulp_service/pulp_service/app/experiments.py b/pulp_service/pulp_service/app/experiments.py index 402f22de..4c663a8c 100644 --- a/pulp_service/pulp_service/app/experiments.py +++ b/pulp_service/pulp_service/app/experiments.py @@ -39,7 +39,7 @@ def run_experiment(exp_id, control, candidate, *, p_candidate, context): logger.info(json.dumps(record)) -def run_lazy_experiment(exp_id, control, candidate, *, p_candidate=0.5): +def run_lazy_experiment(exp_id, control, candidate, *, p_candidate=0.5, repository_id=None): """Dispatch one variant of an A/B experiment over lazily evaluated querysets. control and candidate are zero-argument callables returning equivalent lazy @@ -47,7 +47,8 @@ def run_lazy_experiment(exp_id, control, candidate, *, p_candidate=0.5): building the queryset does not execute it, and callers may chain further filters before evaluation. Latency is attributed per variant through the SQL marker comments in RDS Performance Insights; this log line records only the - dispatch decision for volume and correlation analysis. + dispatch decision for volume and correlation analysis, plus the target + repository when the caller passes repository_id. """ variant = "B" if random.random() < p_candidate else "A" # noqa: S311 logger.info( @@ -57,6 +58,7 @@ def run_lazy_experiment(exp_id, control, candidate, *, p_candidate=0.5): "exp_id": exp_id, "variant": variant, "p_candidate": p_candidate, + "repository_id": str(repository_id) if repository_id else None, "correlation_id": get_guid(), } ) diff --git a/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py b/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py index 4e3810b7..de47aa7e 100644 --- a/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py +++ b/pulp_service/pulp_service/tests/unit/test_interval_content_experiment.py @@ -127,6 +127,7 @@ def test_get_content_experiment_dispatch(repository, content_pks, add_content, m dispatch["event"] == "ab_experiment_dispatch" and dispatch["exp_id"] == EXPERIMENT_ID for dispatch in dispatches ) assert all(dispatch.get("correlation_id") for dispatch in dispatches) + assert all(dispatch.get("repository_id") == str(repository.pk) for dispatch in dispatches) def test_get_content_marks_sql_per_variant(repository, content_pks, add_content, monkeypatch): # noqa: ARG001