{"action":"closed","issue":{"url":"https://api.github.com/repos/TabDigital/redis-rate-limiter/issues/1","repository_url":"https://api.github.com/repos/TabDigital/redis-rate-limiter","labels_url":"https://api.github.com/repos/TabDigital/redis-rate-limiter/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/TabDigital/redis-rate-limiter/issues/1/comments","events_url":"https://api.github.com/repos/TabDigital/redis-rate-limiter/issues/1/events","html_url":"https://github.com/TabDigital/redis-rate-limiter/issues/1","id":114082417,"number":1,"title":"Race condition that leads to a non-expiring redis key","user":{"login":"ldperronevolio","id":7093612,"avatar_url":"https://avatars.githubusercontent.com/u/7093612?v=3","gravatar_id":"","url":"https://api.github.com/users/ldperronevolio","html_url":"https://github.com/ldperronevolio","followers_url":"https://api.github.com/users/ldperronevolio/followers","following_url":"https://api.github.com/users/ldperronevolio/following{/other_user}","gists_url":"https://api.github.com/users/ldperronevolio/gists{/gist_id}","starred_url":"https://api.github.com/users/ldperronevolio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ldperronevolio/subscriptions","organizations_url":"https://api.github.com/users/ldperronevolio/orgs","repos_url":"https://api.github.com/users/ldperronevolio/repos","events_url":"https://api.github.com/users/ldperronevolio/events{/privacy}","received_events_url":"https://api.github.com/users/ldperronevolio/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-10-29T15:58:56Z","updated_at":"2016-04-01T21:50:33Z","closed_at":"2016-04-01T21:50:33Z","body":"A race condition is present in the way redis operations are made, which leads to a client that gets rate-limited forever. (Which happened to me).\r\n\r\n```    opts.redis.multi()\r\n         .setex(tempKey, opts.window, 0)\r\n         .renamenx(tempKey, realKey)\r\n         .incr(realKey) \r\n```\r\n\r\nBasically, what I suspect, is that realKey got expired between the renamenx and the incr operation. INCR behavior on a non-existing key is to create it, but with no expiration. \r\n\r\nIt's hard to reproduce, but in our situation, it's the load balancer health check that triggered the condition, since it always performs the query at the exact same interval.\r\n"}}