Skip to content

Convert Redis Set ID Indices to Sorted Sets for Stable Pagination & Deterministic Ordering - #105

Merged
prodbycorne merged 1 commit into
SmartDropLabs:mainfrom
paris27-A:feat/convert-id-indices-to-redis-sorted-sets
Jul 20, 2026
Merged

Convert Redis Set ID Indices to Sorted Sets for Stable Pagination & Deterministic Ordering#105
prodbycorne merged 1 commit into
SmartDropLabs:mainfrom
paris27-A:feat/convert-id-indices-to-redis-sorted-sets

Conversation

@paris27-A

Copy link
Copy Markdown
Contributor

Closes #82

Summary

This PR replaces Redis Set-based ID indices with Redis Sorted Sets to provide stable, deterministic ordering for paginated list endpoints.

Previously, the affected services retrieved all IDs using SMEMBERS and performed pagination by slicing the resulting array in application code. Since Redis Sets do not guarantee iteration order, clients could encounter duplicate or missing items across pages, even when no writes occurred between requests.

This change adopts Redis Sorted Sets scored by creation timestamp, ensuring consistent newest-first ordering while preserving the existing public API.

Changes

  • Converted Redis ID indices from Sets to Sorted Sets.
  • Replaced SADD with ZADD using Date.now() as the score.
  • Replaced SMEMBERS and application-side slicing with ZREVRANGE for Redis-native pagination.
  • Replaced SREM with ZREM.
  • Replaced total count calculations based on ids.length with ZCARD.
  • Preserved existing API response formats and pagination semantics.
  • Applied the changes consistently across the affected services.

Validation

  • Verified paginated results are returned in a stable, deterministic newest-first order.
  • Confirmed pagination returns each item exactly once across all pages for a static dataset.
  • Ensured no changes to existing API contracts or response shapes.
  • Updated existing tests and added coverage for deterministic pagination behavior where applicable.

Notes

Items created within the same millisecond may receive identical scores. In those cases, Redis deterministically orders members lexicographically by ID, providing stable pagination even though strict creation order for same-millisecond inserts is not guaranteed.

If existing deployments already store these keys as Redis Sets, a migration or clean cutover is required before deployment to avoid Redis WRONGTYPE errors.

@paris27-A

Copy link
Copy Markdown
Contributor Author

Hi, please can a maintainer approve the workflow and review this PR? Thank you.

@prodbycorne
prodbycorne merged commit 01094b3 into SmartDropLabs:main Jul 20, 2026
1 of 2 checks passed
boluwacodes added a commit to boluwacodes/smartdrop-backend that referenced this pull request Jul 22, 2026
scanIds() was converted from SSCAN (plain set) to ZSCAN (sorted set)
by SmartDropLabs#105, but this one assertion still checked mockRedis.sscan instead
of mockRedis.zscan, so it silently asserted 0 > 1 was never reached
via the real code path and would have passed for the wrong reason.
boluwacodes added a commit to boluwacodes/smartdrop-backend that referenced this pull request Jul 22, 2026
SmartDropLabs#105 converted apiKeys.js's id index from a plain Set (sadd/srem/
smembers) to a sorted Set (zadd/zrem/zrevrange) for stable pagination,
but this test's inline Redis mock was never updated, so createKey()
threw "redis.zadd is not a function" for every test that creates a key.
boluwacodes added a commit to boluwacodes/smartdrop-backend that referenced this pull request Jul 22, 2026
Same missing zadd/zrem/zrevrange/zcard/zscan gap as auth.test.js -
airdrops.js's id index and expiry scan also moved to a sorted set
under SmartDropLabs#105. Also removes leftover console.log debugging statements
someone left in while chasing this same failure.
boluwacodes added a commit to boluwacodes/smartdrop-backend that referenced this pull request Jul 22, 2026
alerts.js's id index also moved to a sorted set under SmartDropLabs#105
(zadd/zrevrange/zcard/zrem); this route-level test's Redis mock only
had smembers, so GET /api/v1/alerts 500'd before ever reaching the
pagination assertions it's meant to check.
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.

Redis SMEMBERS-backed pagination is unstable across airdrops, alerts, and API-key listing endpoints

2 participants