Skip to content

add: performance analysis#1881

Draft
tommartensen wants to merge 3 commits into
masterfrom
tm/performance-analysis
Draft

add: performance analysis#1881
tommartensen wants to merge 3 commits into
masterfrom
tm/performance-analysis

Conversation

@tommartensen

Copy link
Copy Markdown
Contributor

No description provided.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tommartensen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: a2035959-7160-4fba-be7e-1b8317b4712d

📥 Commits

Reviewing files that changed from the base of the PR and between c57027b and abad9f5.

📒 Files selected for processing (3)
  • pkg/service/cluster/cluster.go
  • pkg/service/cluster/helpers.go
  • pkg/service/cluster/helpers_test.go
📝 Walkthrough

Walkthrough

Adds Kubernetes label-based filtering for cluster workflows and labels newly created workflows with owner and flavor metadata. Also adds a comprehensive performance and scaling strategy covering bottlenecks, deployment, monitoring, testing, and rollout phases.

Changes

Cluster filtering and scaling

Layer / File(s) Summary
Workflow labels and server-side filtering
pkg/service/cluster/labels.go, pkg/service/cluster/helpers.go, pkg/service/cluster/cluster.go
Workflow owner and flavor labels are added, selector construction moves ownership and flavor filtering to Kubernetes, and cluster listing retains expiration, prefix, and status filtering.
Performance and scaling strategy
performance-analysis.md
Documents performance findings, scaling constraints, deployment recommendations, rollout phases, monitoring, load testing, cost estimates, and mitigations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant clusterImpl.List
  participant buildLabelSelector
  participant ArgoWorkflows
  Caller->>clusterImpl.List: ClusterListRequest and context email
  clusterImpl.List->>buildLabelSelector: Build owner and flavor selector
  buildLabelSelector-->>clusterImpl.List: Kubernetes labels.Selector
  clusterImpl.List->>ArgoWorkflows: ListWorkflows with LabelSelector
  ArgoWorkflows-->>clusterImpl.List: Matching workflows
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so the PR intent can't be assessed from the author's text. Add a brief description of the performance-analysis doc and server-side workflow filtering changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main theme of the changes, which add a performance analysis document and workflow filtering improvements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tm/performance-analysis

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@rhacs-bot

Copy link
Copy Markdown
Contributor

A single node development cluster (infra-pr-1881) was allocated in production infra for this PR.

CI will attempt to deploy quay.io/rhacs-eng/infra-server: to it.

🔌 You can connect to this cluster with:

gcloud container clusters get-credentials infra-pr-1881 --zone us-central1-a --project acs-team-temp-dev

🛠️ And pull infractl from the deployed dev infra-server with:

nohup kubectl -n infra port-forward svc/infra-server-service 8443:8443 &
make pull-infractl-from-dev-server

🔓 You must go to to export an . Your token from the prod infra instance will not work with dev environments.

🚲 You can then use the dev infra instance e.g.:

bin/infractl -k -e localhost:8443 whoami

⚠️ Any clusters that you start using your dev infra instance should have a lifespan shorter then the development cluster instance. Otherwise they will not be destroyed when the dev infra instance ceases to exist when the development cluster is deleted. ⚠️

Further Development

☕ If you make changes, you can commit and push and CI will take care of updating the development cluster.

🚀 If you only modify configuration (chart/infra-server/configuration) or templates (chart/infra-server/{static,templates}), you can get a faster update with:

make helm-deploy

Logs

Logs for the development infra depending on your @redhat.com authuser:

Or:

kubectl -n infra logs -l app=infra-server --tail=1 -f

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/service/cluster/cluster.go (1)

154-180: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Backfill owner labels or keep a fallback. Pre-existing workflows lack labelOwner, so All=false owner queries filter them out and hide them from their owners. A migration/backfill or a transitional annotation-based fallback is needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/service/cluster/cluster.go` around lines 154 - 180, Update the List flow
around buildLabelSelector and ListWorkflows so owner-filtered requests with
All=false still return pre-existing workflows that lack the labelOwner label.
Implement either a migration/backfill for existing workflows or a transitional
annotation-based fallback, while preserving server-side filtering for workflows
with owner labels.
🧹 Nitpick comments (1)
performance-analysis.md (1)

1097-1107: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Frame these as targets, not outcomes. performance-analysis.md:1103-1107 still reads like these numbers are already achieved, while the surrounding section only outlines a validation plan. Tie each figure to an explicit assumption or benchmark, and soften “without further changes” unless that’s demonstrated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@performance-analysis.md` around lines 1097 - 1107, Revise the “Expected
Outcomes” section to present the latency, API-load, availability, and
scalability figures as targets or estimates rather than achieved results. State
the assumptions or benchmark conditions supporting each figure, and replace
“without further changes” in the scalability target with qualified language tied
to validation.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@performance-analysis.md`:
- Around line 14-16: Narrow the “Scaling Blocker” statement in
performance-analysis.md to safe horizontal scaling of background workers,
reflecting the coordination requirement for duplicate side effects while not
implying that stateless request-serving API replicas require leader election.
- Around line 185-189: Update the caching recommendation for
getMostRecentArgoWorkflowFromClusterID() to define authorization-safe cache keys
before implementation. Require keys to include the authenticated principal or
tenant, namespace, and every request filter, matching the email-derived selector
logic in the cluster service, and document that cached list results must never
be shared across authorization boundaries.
- Around line 1007-1012: Correct the GCS API call calculations in the “GCS API
Calls” section: apply the 90% cache hit rate to 2 operations per minute across
100 artifacts, yielding 20 cache-miss reads per minute and approximately 28,800
reads per day. Update the resulting Class A operation cost and “Total Current”
figure to match the corrected projection, including the existing ~$4.34/month
estimate where applicable.
- Around line 232-251: Complete cleanupExpiredClusters by adding explicit
exponential-backoff state that increases after processExpiredClusters errors and
resets after successful processing, while preserving jittered scheduling. Wire
the service-level context used by cleanup goroutines to an explicit cancellation
hook invoked during server shutdown, ensuring cleanupExpiredClusters exits
promptly and does not remain live after termination.
- Around line 942-958: The alert expressions for InfraServerHighLatency and
InfraServerHighMemory need correction. Update the latency expression to apply
histogram_quantile to summed, rate-based *_bucket series grouped by le, and
guard the memory ratio against missing or zero container memory limits (or
establish limits in the deployment configuration) so InfraServerHighMemory
cannot misfire.

In `@pkg/service/cluster/cluster.go`:
- Around line 411-414: Update the owner label value in the workflow labels built
by the surrounding workflow creation logic to use a Kubernetes label-safe
encoding instead of the raw email address. Apply the identical encoding in
buildLabelSelector so labels and owner filtering remain consistent, while
leaving the cluster ID and flavor labels unchanged.

In `@pkg/service/cluster/helpers.go`:
- Around line 271-296: The owner filter in buildLabelSelector must use the same
label-safe encoding as the labelOwner value written in cluster.go. Replace the
raw email used by labels.NewRequirement with the shared encoding/helper, and
update the labelOwner assignment path if necessary so both write and query use
identical encoded values while preserving owner filtering behavior.

---

Outside diff comments:
In `@pkg/service/cluster/cluster.go`:
- Around line 154-180: Update the List flow around buildLabelSelector and
ListWorkflows so owner-filtered requests with All=false still return
pre-existing workflows that lack the labelOwner label. Implement either a
migration/backfill for existing workflows or a transitional annotation-based
fallback, while preserving server-side filtering for workflows with owner
labels.

---

Nitpick comments:
In `@performance-analysis.md`:
- Around line 1097-1107: Revise the “Expected Outcomes” section to present the
latency, API-load, availability, and scalability figures as targets or estimates
rather than achieved results. State the assumptions or benchmark conditions
supporting each figure, and replace “without further changes” in the scalability
target with qualified language tied to validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: e20a386a-102a-4541-a0c8-4d66095fd893

📥 Commits

Reviewing files that changed from the base of the PR and between 2086029 and c57027b.

📒 Files selected for processing (4)
  • performance-analysis.md
  • pkg/service/cluster/cluster.go
  • pkg/service/cluster/helpers.go
  • pkg/service/cluster/labels.go

Comment thread performance-analysis.md
Comment on lines +14 to +16
- **Scaling Blocker:** No leader election or distributed coordination prevents safe horizontal scaling
- **Resource Constraints:** No CPU/memory limits defined for any component
- **Background Load:** Two polling loops list all workflows every 60 seconds per instance

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Narrow the horizontal-scaling blocker claim.

Leader election is required to coordinate the duplicate background side effects shown in pkg/service/cluster/cluster.go:640-690 and 730-780; it is not a blanket prerequisite for scaling the request-serving read path. Reframe this as “safe horizontal scaling of background workers” to avoid unnecessarily blocking stateless API replicas.

As per path instructions, this review focuses on major performance, maintainability, and security risks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@performance-analysis.md` around lines 14 - 16, Narrow the “Scaling Blocker”
statement in performance-analysis.md to safe horizontal scaling of background
workers, reflecting the coordination requirement for duplicate side effects
while not implying that stateless request-serving API replicas require leader
election.

Source: Path instructions

Comment thread performance-analysis.md
Comment on lines +185 to +189
**Solution:**
- Use label selector for `getMostRecentArgoWorkflowFromClusterID()`: `labels.Set{"infra.stackrox.com/cluster-id": clusterID}.AsSelector()`
- Implement watch-based monitoring instead of polling for background loops
- Add caching layer for list results with short TTL (5-10 seconds)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Define authorization-safe cache keys before recommending list caching.

pkg/service/cluster/cluster.go:158-166 derives selectors from the authenticated user’s email. A shared list cache must include the principal/tenant, namespace, and every request filter; otherwise one user could receive another user’s cluster list. Document the cache isolation and authorization contract before implementation.

As per path instructions, this review focuses on major performance, maintainability, and security risks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@performance-analysis.md` around lines 185 - 189, Update the caching
recommendation for getMostRecentArgoWorkflowFromClusterID() to define
authorization-safe cache keys before implementation. Require keys to include the
authenticated principal or tenant, namespace, and every request filter, matching
the email-derived selector logic in the cluster service, and document that
cached list results must never be shared across authorization boundaries.

Source: Path instructions

Comment thread performance-analysis.md
Comment on lines +232 to +251
```go
func (s *clusterImpl) cleanupExpiredClusters(ctx context.Context) {
// Add jitter to prevent thundering herd
jitter := time.Duration(rand.Intn(30)) * time.Second
ticker := time.NewTicker(resumeExpiredClusterInterval + jitter)
defer ticker.Stop()

for {
select {
case <-ctx.Done():
return // Graceful shutdown
case <-ticker.C:
// Use watch API or cached list
if err := s.processExpiredClusters(ctx); err != nil {
// Exponential backoff on errors
}
}
}
}
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Make the shutdown and backoff design complete.

The sample adds a fixed ticker, but does not implement exponential backoff despite claiming it will. The service-level context proposed at lines 283-294 also needs an explicit cancellation hook tied to server shutdown; otherwise the goroutines remain live. Include the retry state and lifecycle wiring in the strategy.

As per path instructions, this review focuses on major performance, maintainability, and security risks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@performance-analysis.md` around lines 232 - 251, Complete
cleanupExpiredClusters by adding explicit exponential-backoff state that
increases after processExpiredClusters errors and resets after successful
processing, while preserving jittered scheduling. Wire the service-level context
used by cleanup goroutines to an explicit cancellation hook invoked during
server shutdown, ensuring cleanupExpiredClusters exits promptly and does not
remain live after termination.

Source: Path instructions

Comment thread performance-analysis.md
Comment on lines +942 to +958
- alert: InfraServerHighLatency
expr: histogram_quantile(0.95, infra_server_list_operation_duration_seconds) > 2
for: 5m
annotations:
summary: "Infra-server list operations exceeding 2s p95 latency"

- alert: InfraServerNoLeader
expr: sum(infra_server_leader_election_status) == 0
for: 1m
annotations:
summary: "No infra-server instance is leader (background tasks not running)"

- alert: InfraServerHighMemory
expr: container_memory_working_set_bytes{pod=~"infra-server.*"} / container_spec_memory_limit_bytes{pod=~"infra-server.*"} > 0.9
for: 5m
annotations:
summary: "Infra-server memory usage > 90% of limit"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant document and nearby sections.
git ls-files performance-analysis.md
wc -l performance-analysis.md
sed -n '900,980p' performance-analysis.md

# Find any references to these metrics or alert rules elsewhere.
rg -n --hidden --no-ignore-vcs \
  'infra_server_list_operation_duration_seconds|infra_server_leader_election_status|container_memory_working_set_bytes|container_spec_memory_limit_bytes|InfraServerHighLatency|InfraServerNoLeader|InfraServerHighMemory' \
  .

# If there are metric definition snippets, inspect them.
rg -n --hidden --no-ignore-vcs 'histogram|bucket|memory limit|limit_bytes|leader_election' performance-analysis.md .

Repository: stackrox/infra

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the specific alert section with line numbers.
sed -n '904,960p' performance-analysis.md | cat -n

# Inspect the earlier resource-constraints statement.
sed -n '1,40p' performance-analysis.md | cat -n
sed -n '500,520p' performance-analysis.md | cat -n

# Look for infra-server resource limits in manifests.
rg -n --hidden --no-ignore-vcs -C 3 'resources:|limits:|requests:|cpu:|memory:' chart/infra-server

# Check whether the latency metric is ever emitted or described as a histogram bucket series.
rg -n --hidden --no-ignore-vcs -C 2 'infra_server_list_operation_duration_seconds(_bucket)?|histogram_quantile|Observe\(|Histogram' .

Repository: stackrox/infra

Length of output: 43161


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the infra-server deployment/chart files.
fd -H -t f 'values.yaml|deployment.yaml|*.yaml' chart/infra-server

# Inspect the infra-server chart for resource limits and the workload definition.
rg -n --hidden --no-ignore-vcs -C 4 'kind: Deployment|resources:|limits:|requests:|container_memory_working_set_bytes|container_spec_memory_limit_bytes|infra_server_list_operation_duration_seconds' chart/infra-server

# Check the server metric configuration around histogram emission.
sed -n '90,120p' pkg/server/server.go | cat -n

Repository: stackrox/infra

Length of output: 494


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the source of the listed metrics in the actual codebase, excluding vendored/dependency dirs.
rg -n --hidden --no-ignore-vcs -g '!ui/node_modules/**' -g '!node_modules/**' \
  'infra_server_list_operation_duration_seconds|infra_server_gcs_artifact_fetch_duration_seconds|infra_server_leader_election_status|container_spec_memory_limit_bytes|container_memory_working_set_bytes' \
  .

# Inspect the infra-server chart for workload resources, if present.
fd -H -t f 'deployment.yaml' chart/infra-server
fd -H -t f 'values.yaml' chart/infra-server

Repository: stackrox/infra

Length of output: 1257


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the infra-server deployment template and values around resource settings.
sed -n '1,220p' chart/infra-server/templates/deployment.yaml | cat -n
printf '\n--- values.yaml ---\n'
sed -n '1,220p' chart/infra-server/values.yaml | cat -n
printf '\n--- argo-values.yaml ---\n'
sed -n '1,120p' chart/infra-server/argo-values.yaml | cat -n

# Search for the custom latency metric implementation or any Prometheus histogram exposition.
rg -n --hidden --no-ignore-vcs -g '!ui/node_modules/**' -g '!node_modules/**' \
  'infra_server_list_operation_duration_seconds|list_operation_duration|EnableHandlingTimeHistogram|Histogram|Observe\(' \
  pkg chart certifier

Repository: stackrox/infra

Length of output: 3679


Fix the Prometheus alert expressions in performance-analysis.md:942-955.

  • histogram_quantile needs the histogram bucket series, e.g. sum by (le)(rate(infra_server_list_operation_duration_seconds_bucket[5m])); the current query won’t calculate p95.
  • chart/infra-server/templates/deployment.yaml defines no memory limits, so the memory ratio has no usable denominator and can misfire; add a guard or set limits first.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@performance-analysis.md` around lines 942 - 958, The alert expressions for
InfraServerHighLatency and InfraServerHighMemory need correction. Update the
latency expression to apply histogram_quantile to summed, rate-based *_bucket
series grouped by le, and guard the memory ratio against missing or zero
container memory limits (or establish limits in the deployment configuration) so
InfraServerHighMemory cannot misfire.

Source: Path instructions

Comment thread performance-analysis.md
Comment on lines +1007 to +1012
**GCS API Calls:**
- Assuming 100 clusters, 2 list operations/minute × 60 min × 24 hr = 2,880 list ops/day
- Each list reads 100 artifacts → 288,000 GCS reads/day
- GCS Class A operations: $0.05 per 10,000 → ~$1.44/day → ~$43/month

**Total Current: ~$103/month** (excluding storage, egress)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the projected GCS-read arithmetic.

With 2 operations/minute, 100 artifacts, and a 90% cache hit rate, the projected miss rate is 20 reads/minute, or about 28,800 reads/day, not 200 reads/minute and 288,000 reads/day. The stated ~$4.34/month cost matches the corrected lower count, so the document is internally inconsistent and currently overstates projected API volume by 10×.

As per path instructions, this review focuses on major performance, maintainability, and security risks.

Also applies to: 1024-1029

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@performance-analysis.md` around lines 1007 - 1012, Correct the GCS API call
calculations in the “GCS API Calls” section: apply the 90% cache hit rate to 2
operations per minute across 100 artifacts, yielding 20 cache-miss reads per
minute and approximately 28,800 reads per day. Update the resulting Class A
operation cost and “Total Current” figure to match the corrected projection,
including the existing ~$4.34/month estimate where applicable.

Source: Path instructions

Comment thread pkg/service/cluster/cluster.go
Comment thread pkg/service/cluster/helpers.go
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.

2 participants