-
Notifications
You must be signed in to change notification settings - Fork 57
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
Rewrite throttle logic to prevent request flooding #1304
Conversation
…limits (fixes #1064) These changes have been made based on the new PR changes from @nestjs/throttler#1304, see: nestjs/throttler#1304
@jmcdo29 I still feel like we should put |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall code looks good and clean. Just add that interface.
@jmcdo29 I have adjusted some small issues and have refactored some of the code. The things to notice are:
|
Everything looks good to me here. @kamilmysliwiec this would be a part of a "breaking" change in that standard use of the library should not change at all, but the underlying API that developers could extend and work with for custom storages would change. I wanted to bring this to your attention before publishing a major release for it in case you noticed anything you wanted addressed. |
@jmcdo29 Hey do you have an ETA on merging this PR? |
I'll likely get this merged and published later this week |
Thanks that will be great, we noticed some issues on request spikes which related to this issue |
Hi @jmcdo29 , any news about merging PR? |
I'll get the docs change started up tomorrow and get the ball rolling on all of that |
Welp, that rebase mucked things up 😅 I'll get that resolved and merged today. |
Removes addRecord() and rewrites addRecord() structure from array to object.
- rewrite storage structure from using arrays to an object - remove getRecord() - adjust addRecord() logic to work with an object rather than array(s)
- add ThrottlerStorageOptions interface - add ThrottlerStorageRecord interface - rename addRecord() to increment() - adjust guard unit test - update readme with the new changes made
@kkoomen heads up, I had to force push to your branch to remove most of those renovate/dependabot commits. All should be clean now though. Just a heads up for next time you work on this library unless you just delete and re-fork. |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: 1303
What is the new behavior?
I've made some adjustments based on my suggestion in #1303 in order to add a single record and retrieve all info in a single function. This also allows external storage providers made by the community to add and retrieve in a single roundtrip (i.e. my redis storage provider).
The initial behavior was that
getRecord()
returned an list of sorted TTL timestamps, then if it didn't reach the limit, it will calladdRecord()
. This change was made based on Redis where I fiddled around on how to prevent this issue. I found out that express-rate-limit is incrementing a single number and returning the information in a single roundtrip, which is significantly faster than how NestJS throttler works by calledgetRecord()
, thenaddRecord
.The rate-limit-redis did have a very fast version with
EVALSHA
. I tried to integrate theEVALSHA
script they used into my own storage provider, which immediately worked. Then I adjust the changes to my version, but that did not work all the way. There were still coming +10 requests through with my version. This version was much faster than before where ±400 requests came through, but still wasn't not perfect. This was becauseSMEMBERS <key>
that I personally used - which returns a list of TTL timestamps from<key>
- seems to be much slower than it is to increment a single number and retrieve this number. Therefore, I made the new logic similar to how express-rate-limit works by requiring two things from theaddRecord()
(which I have renamed in this PR):totalHits
: amount of requests done forkey
timeToExpire
: amount of seconds until thetotalHits
expire forkey
Does this PR introduce a breaking change?
Breaking
ThrottlerStorage
changes:getRecord
addRecord(key: string, ttl: number): Promise<number[]>;
changes toincrement(key: string, ttl: number): Promise<ThrottlerStorageRecord>;
Other information