Skip to content

feat: Report an environment's whole key set in the status resource - #898

Open
keelerm84 wants to merge 1 commit into
mk/SDK-3202/malformed-payloadsfrom
mk/SDK-3203/status-key-arrays
Open

keelerm84 wants to merge 1 commit into
mk/SDK-3202/malformed-payloadsfrom
mk/SDK-3203/status-key-arrays

Conversation

@keelerm84

@keelerm84 keelerm84 commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Summary

Phase 5, the last of forward-porting concurrent multi-key support from v8 (#817) to v9. Stacked on #897; GitHub retargets it to feat/concurrent-keys-v9 as the stack merges.

EnvironmentStatusRep gains sdkKeys and mobileKeys arrays of { key, value, expiry? }. Both are always present rather than omitted, so a consumer can iterate without a nil check: sdkKeys always holds at least the anchor, and mobileKeys is empty for a server-side-only environment.

The scalar fields stay

sdkKey and mobileKey remain, designating which array entry owns the connection to LaunchDarkly and which mobile key is used where only one can be. Asked and decided during review: they are deliberately not replaced by an anchor: true flag on an entry. sdkKey predates concurrent keys and is what consumers read to identify an environment, v8 reports the same pair of fields so one consumer can read both versions, and encoding the designation in two places would let them drift. The rationale is recorded on the field.

expiringSdkKey is removed

One field cannot describe an environment that accepts several keys with different expiries. The soonest-expiring-non-anchor rule phase 3 carried was only there to keep that field, and the metrics reading it, deterministic while the rest of the port landed. Per-key expiry now lives in the arrays.

Metrics re-based

The two instruments #876 derived from ExpiringSDKKey != "" move onto the arrays:

  • per-environment becomes launchdarkly.relay.environment.expiring_keys, a count of that environment's SDK keys carrying an expiry. A bit cannot say how many, and it no longer means "a rotation is in progress" — a key set can hold an expiring key as a steady state.
  • relay-wide keeps launchdarkly.relay.environment.expiring_key.count, still counting environments, now those serving at least one key with an expiry.

Descriptions reworded in status_measures.go and docs/metrics.md. The existing metrics tests caught a name collision when the per-environment gauge was first renamed to .expiring_key.count, which is why the two now have clearly distinct names.

The expect API was already ready

No grammar change was needed. internal/api/status_query_test.go carried a test named "array fields the schema does not have yet", whose comment said the path grammar supports array selectors specifically so they would survive the concurrent-keys change. That test now describes the past, so it is split: addressing sdkKeys at the wrong level still returns 422, and there is new positive coverage for sdkKeys[key=...] and sdkKeys[0] resolving against real data, with a selector that matches nothing returning 412 rather than 422.

Documentation

docs/endpoints.md documented expiringSdkKey=... as a 412 example, which would now be a 422, and its three status-document examples showed only the scalar fields. All updated, plus a short paragraph on why an environment reports several keys and what the scalar fields designate.

Part of SDK-3203, under epic SDK-3188.


Note

Overview
The /status health JSON now reports each environment’s full accepted credential set via always-present sdkKeys and mobileKeys arrays (key, obscured value, optional expiry). Scalar sdkKey / mobileKey stay as the anchor and primary mobile key designators.

expiringSdkKey is removed; rotation and overlap are expressed per entry in sdkKeys. Status building drops soonestExpiringSDKKey in favor of populating those arrays from the accepted key set.

Metrics: per-environment launchdarkly.relay.environment.expiring_keys is a count of SDK keys with an expiry (replacing the boolean expiring_key gauge); relay-wide expiring_key.count still counts environments with any expiring SDK key.

expect probes can assert on sdkKeys[...] (412 when a selector matches no key); docs and tests are updated. Integration tests use expiringSDKKeyIn() over SDKKeys instead of the old field.

Reviewed by Cursor Bugbot for commit 0dadeb2. Bugbot is set up for automated code reviews on this repo. Configure here.

Phase 5, the last of forward-porting concurrent multi-key support from v8
(#817).

EnvironmentStatusRep gains sdkKeys and mobileKeys arrays of { key, value,
expiry? }. Both are always present rather than omitted, so a consumer can
iterate without a nil check: sdkKeys always holds at least the anchor, and
mobileKeys is empty for a server-side-only environment.

The scalar sdkKey and mobileKey fields stay, and designate which array entry
owns the connection to LaunchDarkly and which mobile key is used where only one
can be. They are deliberately not replaced by a flag on an entry: sdkKey
predates concurrent keys and is what consumers read to identify an environment,
v8 reports the same pair, and encoding the designation twice would let the two
drift.

Removes the singular expiringSdkKey. One field cannot describe an environment
that accepts several keys with different expiries, and the soonest-expiring rule
phase 3 carried was only there to keep the field and the metrics reading it
deterministic while the rest of the port landed. Per-key expiry is in the arrays.

The two metrics derived from that field move onto the arrays. The
per-environment gauge becomes a count of the environment's expiring keys rather
than a bit, because a bit cannot say how many, and it no longer means "a rotation
is in progress": a key set can carry an expiring key as a steady state. The
relay-wide gauge still counts environments, now those serving at least one key
with an expiry. Descriptions reworded in the code and in docs/metrics.md.

The expect query API needed no grammar change. Its array selectors were added
for this, and the test asserting they were not yet evaluable is replaced with
coverage of them resolving against real data.
@keelerm84
keelerm84 requested a review from a team as a code owner September 25, 2026 15:19
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.

1 participant