1

We use a rate limiting system which is a slight modification of rate-limit-redis npm. Instead of setting expiry after the multi transaction, which is not atomic, we introduced a 'set' command before 'incr'. The code for the same is:

options.client
  .multi()
  .set(<key>, 0, EX, <expiry_time>, NX)
  .incr(rdskey)
  .pttl(rdskey)
  .exec(function (err, replies) {
    if (err) {
      return cb(err);
    }

    cb(
      null,
      replies[1],
      replies[2]
    );
  });

};

This is the modification to the redis store that express will be using. As you can see, SET command sets the expiry with 'EX' only when the key doesn't already exist (NX). Expiry time is set as 1 minute. For most keys, it's working as we expect it to, but for a few keys we noticed that the key wasn't being reset even after a minute. After digging further, we saw that TTL for those keys is being set as -1

The command returns -2 if the key does not exist. The command returns -1 if the key exists but has no associated expire.

How is the TTL becoming -1 when we are setting it's expiry with SET command. Came across this stackoverflow answer where they had a similar issue with rate limiting system. They were using DECR command instead of DECR. The author of that answer also mentioned using MULTI would solve the problem, but that didn't work for us, since we are already using MULTI.

We also found that the TTL was changing to -1 when SET or INCR commands were failing in the transaction. Going through the logs, we didn't see any occurrence of SET or INCR failing. It could be possible that someone was setting the key without expiry time, but we verified that isn't happening.

Race conditions shouldn't be a problem with redis, especially with a multi transaction. What is causing some keys TTL to become -1, and how can we resolve it?

Mish Nia
  • 31
  • 1
  • 7
  • Is it possible that another code path resets the TTL for these keys? Note that if you `SET` a key that has a TTL, the TTL is removed (unless the `EX\PX\EXAT\PXAT` is used to specify a new TTL value, or when the `KEEPTTL` modifier is specified) – Itamar Haber Oct 21 '21 at 15:07
  • There are 2 services that share this modified redis-store. Both services deal with the same keys, but since we're using NX, if the key already has a TTL, it shouldn't overwrite it. And if in some weird scenario it is overwriting the TTL, it should do so with the expiry time that we mention beside EX. Not sure why -1 comes into picture, especially since SET and INCR are always a success – Mish Nia Oct 22 '21 at 04:15
  • Update: Found a key that was working normally, whose pttl abruptly became -1. Checked the previous request to the same key. The last request and next request (one with pttl -1) were exactly a minute apart. First was at 11:00:24.601 and second at 11:00:25.601. Exactly 1 minute apart, to the millisecond. Is it possible that when the SET operation was taking place the key had not expired, but by the time INCR was supposed to happen, the key expired and hence it incremented the key's value to 1 and pttl became -1? If that's the case, what can we do to overcome this? – Mish Nia Oct 29 '21 at 02:43

0 Answers0