luis's blog

publicado em 28/04/2026

Redis is not just a cache

visualizações

Listen to Cult Member - U Weren't Here I Really Miss You (slowed) while reading!

cookbook: three things you can make with one redis

CCD Chip

same stock, three dishes. each recipe lists what it needs and what can go wrong.


recipe 1: a rate limit that survives crashes

serves: any public endpoint time: one round trip

ingredients

  • one key per caller
  • one counter
  • one ttl
  • one lua script

method

local n = redis.call("INCR", KEYS[1])
if n == 1 then
  redis.call("PEXPIRE", KEYS[1], ARGV[1])
end
return n

the trick is that the increment and the expiry happen in a single command from redis's point of view. the two-command version, INCR then EXPIRE, can crash between them and leave a counter that never resets.

do not: add a transaction "somewhere" to fix a race. make the unit of work smaller than the race.


recipe 2: a lock with an owner

serves: one worker at a time time: 30 seconds, then it releases itself

ingredients

  • SET key token NX PX 30000
  • a unique token per holder
  • an unconditional conditional delete

method

acquire with NX (nobody else holds it) and PX (a crashed holder doesn't lock forever). release with a script that deletes only if the stored token is still yours. otherwise a slow process deletes a lock that already belongs to someone else, and the bug looks like magic.

do not: DEL key. that is not a lock, it's a suggestion.


recipe 3: a queue, and knowing when to leave redis

serves: background jobs time: as long as the job takes

ingredients

  • a list or a stream
  • a worker that can retry

method

LPUSH/BRPOP is enough for "do this later". streams give you consumer groups and acks. for retries with backoff, routing, fanout and dead letters, stop cooking here: that is rabbitmq's kitchen.

do not: choose a queue by throughput. choose it by what it promises when the worker dies mid-job.


plating

all three recipes live in the same daemon, which is the point and the trap. redis is fast and simple, and simplicity makes it easy to forget that "cache", "coordinator" and "broker" are three different jobs with different failure stories.

my rule: start with recipe 1 and 2, graduate to rabbitmq when delivery semantics matter, and never let the cache hold anything i can't rebuild.

image credits

← voltar para o arquivo