class RedisMutex
def initialize(redis: Redis.current)
@redis = redis
end
def with_lock(key, ttl: 60)
token = SecureRandom.uuid
ok = @redis.set(key, token, nx: true, ex: ttl)
return false unless ok
yield
ensure
release(key, token)
end
private
def release(key, token)
lua = <<~LUA
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
LUA
@redis.eval(lua, keys: [key], argv: [token])
end
end
Sometimes you need “only one runner globally” (backfills, refresh jobs). A Redis mutex with TTL avoids deadlocks if the process dies. It’s not perfect, but it’s a solid pragmatic tool.