Skip to content

feat(experimentation): experiment exposures read and refresh endpoints#7754

Open
gagantrivedi wants to merge 4 commits into
mainfrom
feat/experiment-exposures-endpoint
Open

feat(experimentation): experiment exposures read and refresh endpoints#7754
gagantrivedi wants to merge 4 commits into
mainfrom
feat/experiment-exposures-endpoint

Conversation

@gagantrivedi

@gagantrivedi gagantrivedi commented Jun 11, 2026

Copy link
Copy Markdown
Member
  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature. (deferred — flag-gated; docs land with the UI.)
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Contributes to the experimentation exposures panel (v0.1). Follows #7740; UI lands next.

  • GET …/experiments/{id}/exposures/ — returns the stored row ({"exposures": null} before the first compute); never hits ClickHouse.
  • POST …/experiments/{id}/exposures/refresh/ — stamps refresh_requested_at (migration 0007) and enqueues the compute task; 202. Guards: 400 before start, 400 once final, 429 + Retry-After within EXPOSURES_REFRESH_MIN_INTERVAL (5 min).
  • compute_experiment_exposures(experiment_id) — full-window recompute (started_atended_at or now); warehouse errors → record_failure, preserving the last good payload; skips deleted, never-started and final rows.
  • ExperimentExposures.is_final — finality (as_of >= ended_at) defined once on the model and enforced in the task, so no caller can recompute a final row after the warehouse's 90-day event TTL and lose data.
  • tasks now imports models/services, not the reverse; the WarehouseConnection hooks defer their task imports to the enqueue site.

Both endpoints sit behind the existing ExperimentPermission.

How did you test this code?

  • Endpoint and task tests covering: row present/absent/stale-with-error, 202 + enqueue + stamp, 429 with exact Retry-After, finalising refresh allowed vs final row rejected, failure preserves payload, deleted/never-started skips, 403s.
  • pytest tests/unit/experimentation/ — 275 passed; ruff + mypy strict clean.

@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 11, 2026 11:15am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
flagsmith-frontend-preview Ignored Ignored Preview Jun 11, 2026 11:15am
flagsmith-frontend-staging Ignored Ignored Preview Jun 11, 2026 11:15am

Request Review

@github-actions github-actions Bot added api Issue related to the REST API docs Documentation updates feature New feature or request and removed docs Documentation updates labels Jun 11, 2026
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.57%. Comparing base (a9822c3) to head (c48b818).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7754      +/-   ##
==========================================
+ Coverage   98.55%   98.57%   +0.01%     
==========================================
  Files        1454     1460       +6     
  Lines       56000    56489     +489     
==========================================
+ Hits        55193    55682     +489     
  Misses        807      807              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added docs Documentation updates feature New feature or request and removed feature New feature or request docs Documentation updates labels Jun 11, 2026
@gagantrivedi

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces functionality to retrieve and refresh experiment exposures, adding a new refresh_requested_at field, a serializer, a background task for computing exposures, and API endpoints with rate-limiting. The feedback highlights a potential race condition in api/experimentation/views.py where enqueuing the background task immediately with delay() inside a database transaction could cause an IntegrityError if the worker executes before the transaction commits; using transaction.on_commit is recommended to resolve this.

Comment thread api/experimentation/views.py
@github-actions github-actions Bot added the docs Documentation updates label Jun 11, 2026
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request docs Documentation updates labels Jun 11, 2026
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Jun 11, 2026
@gagantrivedi gagantrivedi marked this pull request as ready for review June 12, 2026 07:05
@gagantrivedi gagantrivedi requested a review from a team as a code owner June 12, 2026 07:05
@gagantrivedi gagantrivedi requested review from khvn26 and removed request for a team June 12, 2026 07:05
@gagantrivedi gagantrivedi requested review from Zaimwa9 and removed request for khvn26 June 12, 2026 07:05
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-7754 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api-test:pr-7754 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-7754 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api:pr-7754 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-7754 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-7754 Finished ✅ Results

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  40.7 seconds
commit  c48b818
info  🔄 Run: #17456 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  42.9 seconds
commit  c48b818
info  🔄 Run: #17456 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  42.1 seconds
commit  c48b818
info  🔄 Run: #17456 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  54.2 seconds
commit  c48b818
info  🔄 Run: #17456 (attempt 1)

@github-actions

Copy link
Copy Markdown
Contributor

Visual Regression

19 screenshots compared. See report for details.
View full report

@Zaimwa9 Zaimwa9 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.

Looks good but i'd appreciate logging refreshing errors and potentially a guard against refreshing the exposure data if an experiment has been running past the 90 days TTL?

Comment on lines +41 to +43
except Exception:
exposures.record_failure()
return

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.

Can we log an error here or within record_failure ?

def is_final(self) -> bool:
# Recomputing a final row can only lose data: warehouse events expire.
ended_at = self.experiment.ended_at
return (

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.

Can we also return true when an experiment has been running for more than 90 days and the first buckets data have expired ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants