Skip to content

Comments

perf: optimize feature gates query and improve loading UX#3284

Merged
openshift-merge-bot[bot] merged 1 commit intoopenshift:mainfrom
stbenjam:feature-gates
Feb 19, 2026
Merged

perf: optimize feature gates query and improve loading UX#3284
openshift-merge-bot[bot] merged 1 commit intoopenshift:mainfrom
stbenjam:feature-gates

Conversation

@stbenjam
Copy link
Member

@stbenjam stbenjam commented Feb 19, 2026

Add LIKE pre-filter before regexp_matches to eliminate non-matching rows early, replace window function with DISTINCT ON for the first-seen subquery to avoid join fan-out, enable 4h API response caching, and keep the DataGrid mounted during reloads so it shows a loading overlay instead of unmounting.

Benchmarked against production: response time dropped from ~70s to ~19s (3.7x speedup). Results verified identical across all 39 feature gates.

Summary by CodeRabbit

  • Performance

    • Added caching to the feature gates API endpoint for faster response times.
    • Optimized database queries for improved feature gates data retrieval.
  • Improvements

    • Enhanced Feature Gates interface with better loading indicators.
    • Added toolbar controls for filtering, searching, and downloading feature gates data.

Add LIKE pre-filter before regexp_matches to eliminate non-matching rows
early, replace window function with DISTINCT ON for the first-seen
subquery to avoid join fan-out, enable 4h API response caching, and keep
the DataGrid mounted during reloads so it shows a loading overlay
instead of unmounting.

Benchmarked against production: response time dropped from ~70s to ~19s
(3.7x speedup). Results verified identical across all 39 feature gates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci-robot
Copy link

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Walkthrough

The changes optimize the feature gates database query by replacing window functions with DISTINCT ON for efficiency, add API response caching, and refactor the frontend FeatureGates component to improve loading state management and toolbar functionality.

Changes

Cohort / File(s) Summary
Database Query Optimization
pkg/db/query/feature_gates.go
Converted first-seen feature gate computation from windowed MIN over partitions to DISTINCT ON approach. Added pre-filter on subquery and replaced window-based calculation of first_seen_in fields with direct extraction from release string.
API Caching
pkg/sippyserver/server.go
Added 4-hour cache configuration to the /api/feature_gates endpoint to enable response caching.
Frontend Component Refactoring
sippy-ng/src/tests/FeatureGates.js
Refactored loading state management by resetting state on fetch initiation. Replaced conditional rendering with unified DataGrid component using loading indicator. Expanded DataGrid configuration with toolbar props including download, filter, and sort functionality. Removed redundant useEffect for filter change handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Excessive Css In React Should Use Styles ❓ Inconclusive Cannot locate sippy-ng/src/tests/FeatureGates.js React component file in the repository to assess inline CSS styling practices. Access the React component file from the pull request to verify if inline styles exceed 3-4 properties and assess whether extraction to useStyles pattern is needed.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the primary changes: query optimization (converting window functions to DISTINCT ON, adding pre-filters) and improved loading UX (DataGrid stays mounted to show loading overlay).
Go Error Handling ✅ Passed Go files contain only query definitions and configuration values without executable error handling code.
Sql Injection Prevention ✅ Passed The feature_gates.go file contains a hardcoded SQL query as a static constant with no string concatenation, parameter insertion, or dynamic query construction. The query uses only literal values and is not vulnerable to SQL injection.
Single Responsibility And Clear Naming ✅ Passed The modifications adhere to single responsibility and clear naming principles. Feature_gates.go has a focused query purpose, server.go cache property is simple and non-invasive, and FeatureGates.js uses appropriately named state variables without generic handler patterns.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@openshift-ci openshift-ci bot requested review from deads2k and smg247 February 19, 2026 15:38
@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 19, 2026
Select(`name, release, regexp_matches(name, '\[(FeatureGate|OCPFeatureGate):([^\]]+)\]|install should succeed') AS match`).
Where("release = ?", release)
Where("release = ?", release).
Where("name LIKE '%FeatureGate:%' OR name LIKE '%install should succeed%'")
Copy link
Member Author

Choose a reason for hiding this comment

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

The regexp match is expensive, but LIKE can use index so its much faster, 4x faster

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
sippy-ng/src/tests/FeatureGates.js (1)

276-314: ⚠️ Potential issue | 🟡 Minor

Ensure the loading overlay stops on fetch errors.

Line 276 sets isLoaded false and the grid now uses loading={!isLoaded}; in the error path (Line 309–313) isLoaded never flips back, so the overlay can stick after a failure.

✅ Suggested fix (always end loading)
 const fetchData = () => {
   setLoaded(false)
   setRows([])
+  setFetchError('')
 
   let queryString = ''
   if (filterModel && filterModel.items.length > 0) {
@@
-      .then((json) => {
+      .then((json) => {
         if (json != null) {
           setRows(json)
         } else {
           setRows([])
         }
-        setLoaded(true)
       })
       .catch((error) => {
         setFetchError(
           'Could not retrieve feature gates ' + props.release + ', ' + error
         )
       })
+      .finally(() => setLoaded(true))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sippy-ng/src/tests/FeatureGates.js` around lines 276 - 314, The fetchData
function currently sets setLoaded(false) before the fetch but never resets it on
errors; update fetchData (inside the Promise chain for the fetch in fetchData)
to ensure setLoaded(true) is called on both success and failure — either add
setLoaded(true) in the .catch handler alongside setFetchError, or use a
finally-equivalent (Promise.finally or an async/await try/catch/finally) to call
setLoaded(true) so the loading overlay controlled by isLoaded is always cleared
after the request.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/db/query/feature_gates.go`:
- Around line 19-30: The query in firstSeenQuery (pkg/db/query/feature_gates.go)
naively casts parts of release to INT/INT[] and will fail for non-numeric
releases like "Presubmits"; modify the SQL to extract and cast only the leading
numeric components (or skip non-numeric releases) before casting—for example use
regexp to pull the leading digit groups (e.g., (regexp_matches(release,
'^(\\d+)'))[1]::int for major and similarly for minor, or use regexp_replace to
strip non-digits) and/or add a WHERE clause to exclude releases without numeric
prefixes so the CASTs in firstSeenQuery succeed safely.

---

Outside diff comments:
In `@sippy-ng/src/tests/FeatureGates.js`:
- Around line 276-314: The fetchData function currently sets setLoaded(false)
before the fetch but never resets it on errors; update fetchData (inside the
Promise chain for the fetch in fetchData) to ensure setLoaded(true) is called on
both success and failure — either add setLoaded(true) in the .catch handler
alongside setFetchError, or use a finally-equivalent (Promise.finally or an
async/await try/catch/finally) to call setLoaded(true) so the loading overlay
controlled by isLoaded is always cleared after the request.

@openshift-ci-robot
Copy link

Scheduling required tests:
/test e2e

@neisw
Copy link
Contributor

neisw commented Feb 19, 2026

/lgtm
/hold
release when you are ready

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 19, 2026
@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Feb 19, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 19, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: neisw, stbenjam

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@stbenjam
Copy link
Member Author

/hold cancel

Thanks :)

@openshift-ci openshift-ci bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 19, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 19, 2026

@stbenjam: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot bot merged commit 0c34e5a into openshift:main Feb 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants