Skip to content

fix: don't reset expiration when TTL is zero #209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 30, 2025

Conversation

david-quennoz-reup
Copy link
Contributor

It seems to be possible for PTTL to return zero when a key is really close to expiring but not actually there yet. When this happens the increment script would reset the key's expiration while the count rolls over into the new window, possibly causing clients to be rate limited at lower request rates or for longer periods of time than they should.

The likelihood of this happening is probably low for most use cases, but I have one high-load global rate limit in my app that regularly sees its window bug out to be twice (and sometimes even thrice) as long as it should be.

Just changing the the comparison from <= to < has fixed this is my app. I believe its a safe change as PTTL explicitly returns -1 if the key doesn't yet have a expiration.

Thanks for the great package btw!

@nfriedly
Copy link
Member

Hey, thanks!

I'm traveling and probably won't be able to give this a close look for a few days, but I'll try to remember to come back to this once I'm home. (Or @gamemaker1 might get to it before me.)

One thought that crossed my mind: do you think you could make a test that recreates the error situation from before the fix and behaves correctly after?

@gamemaker1
Copy link
Member

Thanks for this PR @david-quennoz-reup! I think the change is good, and all the library tests are passing so it shouldn't break any existing rate limiters.

I do agree with @nfriedly, it would be better to merge this change along with a test for this case.

@gamemaker1 gamemaker1 requested a review from nfriedly May 29, 2025 13:50
@gamemaker1
Copy link
Member

I tried adding a test for this but failed - please see my comment in the test file. For now, I have marked the test so that Jest skips it. I think we should merge the PR as is and publish a release since it seems to be fixing the issue without affecting behaviour in any other cases.

Please let me know what you think @nfriedly.

@nfriedly
Copy link
Member

Let me take a stab at the test, but if I can't get it working within a day or so, go ahead with your plan.

@gamemaker1
Copy link
Member

Sounds good, thanks!

@nfriedly
Copy link
Member

Ok, I think I'm ready to throw in the towel on this one. I tried a few different things, including real time instead of mocking the clock, and mocking/monkey-patching various things, but ioredis-mock is pretty locked down and I couldn't find anything accessible that would let me advance the clock during evaluation of the lua script, and that's what would trigger the bug.

@nfriedly nfriedly merged commit 5e9297f into express-rate-limit:main May 30, 2025
8 checks passed
@nfriedly
Copy link
Member

Ok, this is now merged in and released in v4.2.1. It should be published to npm by CI shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants