Question - Throttler Per UserContext
ilanl opened this issue · comments
Let's say I have a socket server that receives on websocket a message
ADD_TASK
data: { userId: 1 }
I would like to throttle the usage , so I'm decorating with:
@Throttle(2, 10)
@SubscribeMessage('ADD_TASK')
onAddTask(client: Socket, data: { userId: number }): void {
... do something only if throttling okay per userId (not per socketId)
}
I was under the impression I could pass a function to the throttle to use the context on the request.
I don't want to throttle globally but per userId, but the event is the same for all.
I'm not sure I understand the question. You can set what tracker the guard is doing by overriding the handleRequest
method which takes in the ExectuionContext
, limit
, and ttl
and you can set up what to throttle by
Sounds good. I'll do that!
I'm not sure I understand the question. You can set what tracker the guard is doing by overriding the
handleRequest
method which takes in theExectuionContext
,limit
, andttl
and you can set up what to throttle by
Sorry I didn't quite get that, Can you provide a minimal example?
It's kind of hard to give a general minimum example because the use case changes from person to person. But if you just need to rate limit based on something like user id and not per route you could do something like
@Injectable()
export class UserThrottlerGuard extends ThrottlerGuard {
getTracker(req: Request) {
return req.user.id;
}
generateKey(context: ExecutionContext, sufix: string) {
return suffix;
}
}
And now it's based on the userid instead of the class name, handler, and IP
It would be nice if this feature can be added to the module, or at least mention it in the doc
PRs for the docs are always welcome at nestjs/docs.nestjs.com
For anyone trying to configure this on a single route (the other routes use a global default throttler), use
export const SkipGlobalThrottle = () => SetMetadata('skipGlobalThrottle', true);
@Injectable()
export class GlobalThrottleGuard extends ThrottlerGuard {
async canActivate(context: ExecutionContext) {
const skipGlobalThrottle = this.reflector.get<boolean>(
'skipGlobalThrottle',
context.getHandler(),
);
if (skipGlobalThrottle) {
return true;
}
return super.canActivate(context);
}
}
@SkipGlobalThrottle() // we need to skip global throttle as the settings below apply to it instead
@Throttle({
default: {
limit: 10,
ttl: hours(1),
},
})
@UseGuards(UserThrottlerGuard)