Skip to content

fix(LaunchDarkly): Rate limited requests retry using the latest Retry-After value - #8965

Open
yoarajota wants to merge 1 commit into
Flagsmith:mainfrom
yoarajota:fix/launchdarkly-rate-limit-retry-after-per-attempt
Open

yoarajota wants to merge 1 commit into
Flagsmith:mainfrom
yoarajota:fix/launchdarkly-rate-limit-retry-after-per-attempt

Conversation

@yoarajota

@yoarajota yoarajota commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor
  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

launch_darkly_backoff hands backoff a wait generator. backoff calls wait.send(exc) after every failed attempt, but _wait_gen assigned exc once, before its loop, and never from the value returned by yield retry_after. Every retry therefore recomputed its wait from the first failed response.

On main (910356d), with a mocked endpoint that answers 429 with Retry-After: 1, then 5, then 20, then 200, the client sleeps for 1, 1 and 1 seconds (plus up to one second of jitter) instead of 1, 5 and 20. It sends two requests earlier than LaunchDarkly asked. Each can hit the limit again and use up one of the BACKOFF_MAX_RETRIES attempts. The comment above the function says the client must wait the time given in Retry-After or X-Ratelimit-Reset.

The same stale value decides whether to retry at all. A 429 followed by a 500 keeps retrying the 500 for as long as the first response said 429.

  • _wait_gen now reads each sent exception: exc = yield retry_after. A response that is not a 429 ends the generator, so backoff gives up and _handle_giveup re-raises that error. A 500 after a 429 now fails immediately instead of being retried.

I did not touch Retry-After: 0, which is falsy and is not retried. It is a separate case.

Review effort: 1/5

How did you test this code?

Added two tests to tests/unit/integrations/launch_darkly/test_client.py, using requests_mock and a patched backoff._sync.time.sleep:

  • test_launch_darkly_client__rate_limit_changing_retry_after__waits_latest_value: 429 with Retry-After 1, 5, 20, then 200. Asserts the waits are 1, 5 and 20 seconds before jitter.
  • test_launch_darkly_client__rate_limit_then_server_error__raises_without_retry: 429, 500, 200. Asserts an HTTPError with status 500 after two calls.

With client.py checked out from main, both fail ([1, 1, 1] == [1, 5, 20], and DID NOT RAISE) and the other 14 client tests pass. With the fix, all 16 pass.

Also ran, against a local Postgres 15.5:

  • pytest tests/unit/integrations/launch_darkly/: 67 passed.
  • mypy integrations/launch_darkly tests/unit/integrations/launch_darkly/test_client.py: no issues. The new yield carries a type: ignore[assignment] like the existing one, because backoff.on_exception types wait_gen as Generator[float, None, None].
  • ruff check and ruff format --check on both paths: clean.

The full make test suite and pre-commit were not run.

View guided diff

…-After value

The backoff wait generator read the retry information from the first
failed response only, so later retries ignored the Retry-After or
X-Ratelimit-Reset sent with the most recent 429, and kept retrying after
a non-429 error.
@yoarajota
yoarajota requested a review from a team as a code owner November 14, 2026 14:39
@yoarajota
yoarajota requested review from khvn26 and removed request for a team November 14, 2026 14:39
@vercel

vercel Bot commented Nov 14, 2026

Copy link
Copy Markdown

@yoarajota is attempting to deploy a commit to the Flagsmith Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the api Issue related to the REST API label Nov 14, 2026
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

_wait_gen now receives each exception from the backoff framework and yields the corresponding retry delay. New tests check waits for successive 429 responses and verify that a 500 response after a 429 raises HTTPError without sending another request.

Estimated code review effort: 2 (Simple) | ~8 minutes

Merge Risk: Minimal · up to b5aa1

The change makes LaunchDarkly retries use each latest rate-limit response and stop after a non-429 error. It is well tested and narrowly scoped, with no known merge-blocking risk.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: af38991f-e5a9-4052-9b78-2a76c6c3be52
Commits

Reviewing files that changed from the base of the PR and between 910356d and b5aa1fd.

Files selected for processing: 2

  • api/integrations/launch_darkly/client.py
  • api/tests/unit/integrations/launch_darkly/test_client.py

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Requires human review: Auto-approval skipped because this PR is from an external contributor.

View guided diff | Re-trigger cubic

@codecov

codecov Bot commented Nov 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.04%. Comparing base (910356d) to head (b5aa1fd).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8965      +/-   ##
==========================================
- Coverage   98.91%   98.04%   -0.88%     
==========================================
  Files        1708     1708              
  Lines       71826    71838      +12     
==========================================
- Hits        71046    70431     -615     
- Misses        780     1407     +627     

☔ 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.

This branch has not been deployed

No deployments
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant