Design rate-limit, scheduler, expiration, and secondary sorted-set indexes with explicit truth, cleanup, reliability, topology, and rollback boundaries.

Use Sorted Sets for Rate Limits, Schedulers, Expiration Indexes, and Secondary Access Paths

Choose hashes, Redis JSON, or many keys from structure, update/query patterns, expiration granularity, memory/cardinality, indexing, ACL boundaries, and migration evidence.

Advanced165–200 minutesOperational sorted-set capstoneRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart's architecture now contains several sorted-set patterns. The final lesson turns them into an operational design discipline: a rate-limit window, a due-time scheduler index, an explicit expiration index, and a secondary access path. The key lesson is that the sorted set is often an index; correctness still depends on the authoritative state, cleanup, atomic transitions, and failure recovery.

01

Design sorted-set rate-limit, scheduler, expiration-index, and secondary-access-path models.

02

Distinguish discovery/order from ownership, acknowledgment, deletion, and business truth.

03

Use bounded range reads and explicit cleanup to control growth.

04

Identify race conditions between primary data and secondary indexes and plan reconciliation.

05

Assess hot-key, Cluster, persistence, retry, memory, latency, and migration implications.

Exact lab baseline

All Chapter 06 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from Docker Official Image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, host publication 127.0.0.1:6379, TLS disabled only because traffic stays on loopback, default ACL user disabled, named ACL users atlasmart-app and academy-admin, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data volume, and no explicit Redis maxmemory limit or eviction policy. The primary interface is the redis-cli shipped in the same pinned image. Mandatory examples use only bounded synthetic keys under atlasmart:ch06:*.

1. Pattern anatomy: member identity + ordering score + lifecycle

Pattern Member Score Authoritative truth
Sliding-window rate limit unique request ID request timestamp application/API policy + request outcome
Delayed scheduler job ID due timestamp job/workflow record
Expiration index object ID desired expiry timestamp object/retention policy
Secondary time index entity ID created/updated timestamp entity record

2. Rate-limit index: prune, add, count, decide

A per-subject sorted set can represent requests within a moving horizon. The design must define whether the current request is added before or after checking, inclusive boundaries, duplicate request IDs, and how concurrent clients make one decision atomically.

redis-cli · deterministic rate-window mechanics
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:ratelimit:user7docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:ratelimit:user7 100 req:a 120 req:b 170 req:cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZREMRANGEBYSCORE atlasmart:ch06:ratelimit:user7 -inf 110docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCOUNT atlasmart:ch06:ratelimit:user7 111 170docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch06:ratelimit:user7 0 -1 WITHSCORES

This demonstrates data mechanics only. A production limiter should combine the race-prone multi-command decision atomically and define TTL/cleanup for idle subject keys; Chapter 23 does that design explicitly.

3. Scheduler index: discovery is not delivery

For scheduled work, query members with score ≤ now. After discovery, the system needs a claim state, retry deadline, idempotency key, completion state, and recovery path. A sorted set provides ordering; it does not provide a Pending Entries List like Streams.

redis-cli · due discovery only
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:schedulerdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:scheduler 1000 job:a 2000 job:b 3000 job:cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch06:scheduler -inf 2100 BYSCORE LIMIT 0 10 WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:scheduler

If you remove a job when it is claimed, maintain durable processing state elsewhere or in another explicit structure. If you leave it in place, prevent multiple workers from acting concurrently. Either way, “ZRANGE found it” is not an acknowledgment protocol.

4. Expiration index: TTL and business retention are different mechanisms

An explicit sorted-set expiration index is useful when an application must discover objects by planned retention time, perform custom archival/deletion, or coordinate cleanup across data stores. Redis key TTL can remove a Redis key automatically; a sorted-set expiration index is an application-managed schedule and should not be presented as an exact timer.

redis-cli · expiration index fixture
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:expiry-indexdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:expiry-index 100 customer:temp1 150 customer:temp2 500 customer:temp3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch06:expiry-index -inf 200 BYSCORE WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZREMRANGEBYSCORE atlasmart:ch06:expiry-index -inf 200docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:expiry-index

The removal above only removes index members. It does not delete the authoritative customer records. A cleanup worker must perform and verify the actual retention action, then reconcile the index.

5. Secondary access paths need reconciliation

Suppose atlasmart:order:9001 is authoritative and atlasmart:ch06:orders-by-time is a secondary sorted-set index. A failure can happen after one is updated but before the other. That makes the index stale even though every Redis command involved was individually atomic.

redis-cli · simulate index drift safely
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:primary:9001 atlasmart:ch06:orders-by-timedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SET atlasmart:ch06:primary:9001 paiddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:orders-by-time 100 order:9001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:primary:9001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch06:orders-by-time 0 -1 WITHSCORES

The index still contains order:9001 after the synthetic primary key is deleted. Repair requires transactional/function coupling where feasible or a reconciliation process that can detect and remove stale index entries.

6. Wrong approach: one global hot key for every tenant

A global leaderboard, scheduler, or limiter can become a write/read hot key even when each operation has good asymptotic complexity. In Redis Cluster, one key maps to one slot and one primary. A better partition key may be tenant, region, time bucket, or workload class—provided cross-partition queries and correctness requirements remain manageable.

7. Cleanup strategy is part of capacity planning

For every sorted-set index, write down the maximum expected live members, insert rate, cleanup cadence, maximum catch-up delete, largest range response, and behavior after a cleanup outage. Measure ZCARD, MEMORY USAGE, command latency, and application response bytes. No universal “safe sorted-set size” replaces workload measurement.

8. Persistence, replication, and retries

AOF/RDB persistence can recover the Redis index according to configured durability windows; asynchronous replication can fail over with some uncertainty. Neither proves that an external email was sent, an order was charged, or an object was deleted. Retried clients may also face ambiguous outcomes after network loss. Design idempotent operations and reconciliation around stable business IDs.

9. Cluster locality and hash tags

A single sorted set needs no multi-key locality, but workflows that atomically combine index and state keys or use multi-key ZUNION/ZINTER need Cluster-aware design. Hash tags can co-locate related keys, but overusing one tag creates a hot slot. Chapter 21 will revisit slot calculation, MOVED/ASK routing, and resharding; this chapter only requires you to record the locality assumption.

10. Search/index boundary

Sorted Sets are excellent one-dimensional numeric/lexicographic access paths. They are not a general substitute for Redis Search indexes over HASH/JSON documents. If AtlasMart needs filters such as category + stock + text relevance + geography, forcing those predicates into composite sorted-set members creates brittle application-side indexing. Chapter 09 covers Search schemas and their memory/write costs.

11. Operational checklist

Concern Question to answer before production
Correctness What is authoritative, and what can be stale?
Ordering What exactly does the score mean? How are ties handled?
Atomicity Which multi-command transitions may interleave?
Retention How are old members removed? What if cleanup stops?
Reliability What survives worker/client failure? How is work retried?
Capacity Expected cardinality, skew, memory, response sizes, p99 latency?
Topology Standalone/replication/Sentinel/Cluster; required slot locality?
Security Which ACL key patterns/commands are allowed? TLS in production?
Migration How is a new index backfilled, verified, cut over, and rolled back?

12. Reproducible capstone lab

Build three bounded indexes, inspect them, then clean only Chapter 06 fixtures.

redis-cli · Chapter 06 capstone
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:cap:window atlasmart:ch06:cap:due atlasmart:ch06:cap:expirydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:cap:window 10 r:1 20 r:2 30 r:3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZREMRANGEBYSCORE atlasmart:ch06:cap:window -inf 10docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:cap:due 100 j:1 200 j:2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch06:cap:due -inf 150 BYSCORE WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:cap:expiry 50 x:1 500 x:2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch06:cap:expiry -inf 100 BYSCORE WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:cap:windowdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch06:cap:window

Verification: the window retains r:2/r:3, j:1 is due at 150, x:1 is selected for expiration work, and no command touches unrelated keys. Cleanup with DEL atlasmart:ch06:cap:window atlasmart:ch06:cap:due atlasmart:ch06:cap:expiry.

13. Migration and rollback judgment

When introducing a sorted-set secondary index, backfill from authoritative data, compare counts and sampled records, dual-write only with an explicit failure/reconciliation plan, cut reads over gradually, and keep a rollback path that does not depend on deleting the old source immediately. For a ranking-policy change, version the destination key or policy so old and new scores can be compared before replacement.

14. Production judgment

Sorted Sets are a strong primitive for score-ordered unique membership and bounded range queries. They are only one component of rate limiters, schedulers, retention workflows, and secondary indexing systems. Production readiness requires atomic transitions, idempotency, reconciliation, capacity/headroom, hot-key strategy, Cluster locality, security, monitoring, failure injection, and rollback—not just correct redis-cli syntax.

15. Summary and bridge to Streams

Chapter 06 established score/rank semantics, safe range queries, time-based indexes, weighted aggregation, cleanup, and operational boundaries. Chapter 07 introduces Redis Streams, where append IDs, retained entries, consumer groups, pending ownership, acknowledgment, and replay solve a different class of event/work-delivery problem.

Check your understanding

  1. What does a sorted-set scheduler natively provide?
  2. Does removing an item from an expiration index delete the underlying object?
  3. Why can a secondary index become stale?
  4. What is the main risk of one global scheduler key in Cluster?
  5. When should Redis Search replace a sorted-set access path?
Review the answers

Numeric ordering and bounded discovery by due score; ownership/ack/retry are separate.

No. It only removes the index member.

Primary and index updates can fail/interleave independently unless coupled and reconciled.

One key maps to one slot/primary and can become a hot key.

When the query requires richer multidimensional/text/structured predicates rather than one score/lex ordering.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.