-
-
Notifications
You must be signed in to change notification settings - Fork 63
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
feat: allow function allowList and keyGenerator to be async/await #256
Conversation
I think isn't need add new unit test, but if is necessary pls tellme |
It seems that your code is broken. |
@DiogoMarques2003 |
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.
Those two functions are synchronous on purpuse. Making them asynchronous and allowing I/O operations will defeat the purpose of this module.
But @mcollina i need consult the database in this functions, and the preValidation is executed after the ratelimit system |
onRequestRateLimiter is already async. If you think that the await in front of the two potential async functions is a performance bottleneck, we could detect if one of those methods is async like this const asyncFunctionPrototype = Object.getPrototypeOf(async function() {});
function isAsyncFunction(v) {
return (
typeof v === 'function' &&
Object.getPrototypeOf(v) === asyncFunctionPrototype
);
}; and if so have a implementation were we have await and another one were we dont await. But again, onRequestRateLimiter is async. |
@Uzlopak i need to do this on the allowList and keyGenerator functions: can i do this databases requests in other place ? |
I was answering mcollina The only reason to reject this PR would be for me, when the performance decreases. And awaiting a non async function decreases the performance. So if the worry of mcollina is that we decrease the perf. by unnecessary awaiting then we can check if we either have an async function and then use it with await or sync methods and dont await. But this means some refactoring to avoid simply duplicating the current function. |
oh ok ok |
Got any reading material around this @Uzlopak? Is it that is awaiting a sync function causes the returned value become a resolved Promise object, and the Promise causes overhead? |
I dont think that await wraps a sync method into a Promise. I only had this issue once about 3 years ago: A sync function was awaited. When I removed the await from the sync-function the unit test became flaky. Investigating further, it revealed a very tight race condition in the sync-function. By awaiting the sync function it resulted in a short delay, which concealed the underlying race condition. I never investigated it further. |
The problem is not about promises but rather as a conscious design decision when implementing this module: providing some limited protection against API misuse and DoS attacks. If we need to check against a database to load some data, you are executing a database query before the check, and therefore you are likely vulnerable. In other terms: looking those things up from a database is counterproductive. This PR makes it simpler to do something insecure and I'm not convinced we should support it. You can achieve what you want by adding an |
Can you show an example to add the database requests in |
Something like this should work app.addHook('onRequest', async (req) => {
// Don't do this, it's very unsafe
const { id, allowList } = await callMyDb()
req.aLongPropertyName = id
req.aLongPropertyName2 = allowList
})
fastify.register(require('@fastify/rate-limit'), ...) |
The max function is async, so maybe can also be |
Ok, I'm sold. Let's make this possible. |
lol, I will give the approval so that you dont have to :D |
I rerun the workflow, but it seems that the tests are now flaky with the additional awaits. |
this is strange because on my computer they all ran correctly |
It may depend on the node.js version. Here are the logs of the run: It seems that the namespace test is always failing. |
Maybe, i'm using version 16.6.0 |
@Eomm any soluction for this ? |
The CI is green https://github.com/fastify/fastify-rate-limit/actions/workflows/ci.yml So there should be something here that has changed some function order execution I can't debug this PR very soon What I would do is: 1- add a check to choose if run the |
for some reason myFunction.constructor.name don't exists |
it was a code example, you need to use your own function |
Should not it be |
@Eomm |
Green I think the constructor check would be good in any case |
You can actually use a prototype check const asyncFunctionPrototype = Object.getPrototypeOf(async function() {})
function isAsyncFunction(v) {
return (
typeof v === 'function' &&
Object.getPrototypeOf(v) === asyncFunctionPrototype
)
} |
@Eomm |
|
@Eomm |
I'm ok landing it, there is a blocking review from @mcollina |
PTAL |
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.
lgtm
Checklist
npm run test
andnpm run benchmark
and the Code of conduct