Repository navigation
chore: release main - #519
Merged
Merged
Conversation
github-actions
Bot
force-pushed
the
release-please--branches--main
branch
from
July 19, 2024 17:03
fff6c56 to
ca03d66
Compare
kinyoklion
approved these changes
Jul 22, 2024
Contributor
Author
|
π€ Created releases: |
tanderson-ld
added a commit
that referenced
this pull request
Sep 28, 2026
β¦off (#2045) ## Summary Adds a reusable retry controller to `@launchdarkly/js-sdk-common` that owns retry tracking, health checking, and delay calculation for long-running components. This is the foundation for RETRY-spec conformance in the Node server SDK (SDK-2790); the data-source wiring that consumes it arrives in a follow-up PR. **There are no consumers in this PR** β the additions are unused by product code and exercised only by tests. The design ports the controller pattern from the Python server SDK ([python-server-sdk#522](launchdarkly/python-server-sdk#522), wired in [#519](launchdarkly/python-server-sdk#519)), with deliberate differences noted below. ## What's where - **`src/datasource/retry/`** β the retry mechanics: the `RetryState` interface and its `createRetryState` factory (the controller), the `ResetPolicy` interface with its two implementations (`AfterHealthyFor` for streaming's healthy-duration reset, `AfterConsecutiveSuccesses` for polling's two-in-a-row reset), and the `forStreaming`/`forPolling` factories that bind the standard values (1sβ30s normal and 5minβ1hr extended regimes; 60s healthy window; two-success polling reset) with warn-and-default validation of the configured delay. - **`src/errors.ts`** β failure classification, placed beside the legacy helper it supersedes: `FailureKind` (`'normal' | 'unexpected'`), `classifyHttpStatus` (400/408/429 and 5xx and non-error statuses are normal; any other 4xx is unexpected), and `classifyTransportFailure` (always normal β in an all-HTTPS system certificate failures can't be reliably distinguished from transient faults). `isHttpRecoverable` now delegates to `classifyHttpStatus` β one table, no drift β and is documented as superseded; it stays undeprecated because the event-delivery pathway still legitimately consumes it until that pathway migrates. ## Design points for review - **`RetryState` is an interface, not a class.** `createRetryState(config)` returns it, backed by a closure over local state; `forStreaming`/`forPolling` return the interface. This keeps the publicly exposed surface an interface (per the repo's prefer-interfaces guideline) and lets future mutators be added additively. The `ResetPolicy` implementations stay classes, since the `ResetPolicy` interface already fronts them everywhere they are consumed. - **Clockless seams.** No method of `RetryState` or `ResetPolicy` takes a timestamp. Time lives in exactly one place: `AfterHealthyFor`'s constructor-injected clock, defaulting to a monotonic source (`performance.now()`, with a `Date.now` closure fallback for exotic runtimes). The controller itself holds no clock; its only injectable is `random`, for deterministic jitter tests. (The parameter is named `clock` rather than the codebase's `timeStamper` deliberately β it is not a timestamp source.) - **Ceiling-bounded backoff, no exponent constant.** The delay computation compares the base against the ceiling scaled *down* (`base >= max / 2**exponent`) rather than scaling the base up, so nothing can overflow the ceiling β the same compare-before-shift structure as the .NET implementation, expressed in lossless power-of-two float math. A zero base (legal: the spec forbids flooring server-directed retry values) short-circuits, closing a `0 Γ Infinity = NaN` edge otherwise reachable when a zero-valued server-directed retry is followed by very many failures. - **A configured delay above the normal ceiling clamps to it.** In the normal regime the ceiling wins, matching the literal spec (1.3.2 + 1.4.2) and the majority of the SDK fleet (Go, Java, .NET). The extended regime is the opposite: its bounds are floored at the configured delay, which spec requirement 1.5.4.1 mandates ("a delay or ceiling that applies after an `unexpected` failure MUST NOT be less than the component's initial delay"). - **`applyServerDirectedRetry(ms)`** β the SSE `retry:` entry point: sticky base that takes precedence over the regime's initial delay (including the extended regime's), doubling restarted, ceiling still applies, survives a healthy reset. Wire-level validation and the 1-hour cap live in the SSE library ([launchdarkly/js-eventsource#40](launchdarkly/js-eventsource#40)), not here. - **Post-success wait = operating cadence**, even while the retry state is raised β a recovering poller returns to schedule immediately rather than serving one more extended-regime wait. ## Testing 89 tests across three suites (584 package-wide, all green): - `RetryState.test.ts` (48) β exact delay ladders for both regimes under injected clock/random (including the 5m/10m/20m/40m/1h/1h extended ladder), regime transition/ratchet/re-arm, anchor-once healthy-stretch discrimination, reset-before-count ordering, fast-second-poll cadence, poll-interval wait floor under real jitter, jitter range with the maximal-draw boundary (the exact-`T/2` tie) and distinctness assertions, server-directed retry semantics (replace/clamp/persist/reject-invalid/later-wins, precedence over both regimes' initial delays, `retry: 0` staying finite through 1,100 failures), normal-ceiling clamp and regime-collapse cases, the extended-floor mandate under direct construction, flapping-never-ratchets, high-n robustness, and factory validation matrices. - `ResetPolicy.test.ts` (8) β the policy seam directly: threshold boundary, anchor-once under repeated healthy reports, failure-clears, consecutive-success counting, and both default-clock closures (monotonic and the `Date.now` fallback). - `errors.test.ts` (33) β the full classification matrix including boundary and non-error statuses, transport classification, and parity pins on the legacy `isHttpRecoverable` truth table through the delegation. The `src/datasource/retry` module is at 100% statement, branch, function, and line coverage. Coverage was cross-checked against the Python, Java, Go, and .NET RETRY test suites; the one technique deliberately not ported is .NET's `BigInteger`/randomized reference sweeps, which exist to exercise 64-bit integer shift surfaces that JS float arithmetic does not have. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Introduces a **RETRY-spec-oriented retry controller** in `@launchdarkly/js-sdk-common` as shared library code onlyβ**no data sources or SDKs call it yet**; follow-up PRs will wire streaming/polling. > > Adds `src/datasource/retry/` with **`RetryState`** (`createRetryState`, `forStreaming`, `forPolling`): exponential backoff with jitter, normal vs **extended** regimes after `unexpected` failures, pluggable **`ResetPolicy`** (healthy-for duration for streaming, consecutive successes for polling), and **`applyServerDirectedRetry`** for SSE `retry:` values. **`errors.ts`** gains **`FailureKind`** plus **`classifyHttpStatus`** / **`classifyTransportFailure`**; **`isHttpRecoverable`** now delegates to the same rules. > > New retry APIs are re-exported from the datasource barrel and package **`index`**. CI **package size limit** for common ESM rises **29β―000 β 29β―500** bytes. Coverage is **89 new tests** across retry and error classification. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7f529cf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
π€ I have created a release beep boop
react-native-client-sdk: 10.3.0
10.3.0 (2024-07-19)
Features
Bug Fixes
This PR was generated with Release Please. See documentation.