Skip to content

API version 20240415 removed race-free flag enumeration: offset pagination can skip/duplicate flags under concurrent archival #134

Description

@keeely

Regression

Before 20240415, GET /api/v2/flags/{projectKey} returned the full set in a
single atomic response — a race-free enumeration. 20240415 switched it to
offset pagination (limit/offset, default 20) with no race-free
alternative
.

LD-API-Version GET /flags behaviour
20191212, 20210729, 20220603 Full set in one response, no _links.next — atomic snapshot
20240415 (current) Paginated, limit=20 default, _links.next present — not race-free

_links.next is not a cursor. Its href is just …&limit=20&offset=20
offset pagination re-encoded as a link, so following it is identical to
incrementing offset and inherits the same race. A real cursor would carry an
opaque, position-stable token ("resume after key X"), not a numeric offset.
Quick test: if next.href contains offset=, it's position-based and races.

Offset pagination isn't a consistent enumeration: archiving a flag mid-walk
removes it from the archived:false set, shifting all later offsets down by one,
so a flag present for the entire walk can be skipped (unarchive → duplicate).
The unpaged behaviour now only survives on the deprecated versions above, so
once those are enforced, no supported version offers race-free enumeration at all.

Reproduction

# pre-20240415: one atomic page, no next link
curl -s -H "Authorization: $LD_TOKEN" -H "LD-API-Version: 20220603" \
  ".../flags/$PROJECT?filter=archived:false" \
  | jq '{count:(.items|length), hasNext:(._links|has("next")), total:.totalCount}'
# count == totalCount, hasNext == false

# 20240415: paginated, and next.href is offset-based
curl -s -H "Authorization: $LD_TOKEN" -H "LD-API-Version: 20240415" \
  ".../flags/$PROJECT?filter=archived:false" \
  | jq '{count:(.items|length), next:._links.next.href, total:.totalCount}'
# count == 20, next ends in "&offset=20"

Skip race on 20240415: page through ?filter=archived:false; archive any flag
behind the current offset; subsequent offsets shift down and the flag at the next
page boundary is never returned.

Request

Restore race-free complete enumeration on a supported version. Not asking to
revert to unpaged — cursor/keyset pagination keeps the paging model while
being immune to offset shift. (For dotted keys, an S3-style prefix+delimiter
listing would also give bounded, atomic per-subtree pages.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions