Anyone got a server side example of _.throttle

Hi, trying to throttle a call to a server side function inside a Method. I have tried to Meteor.wrapAsync the _.throttle but getting a Fibers related exceptions… Does anyone have an example please?

For example,

someMethod() {

  const someFunction = _.throttle(() => {
    console.log('hello');
   some other Meteor stuff , like async method calls, etc
  }, 200);
  
  for ( some loop) {
     someFunction();

 }
}

I’ve tried to Meteor.wrapAsync the someFunction but still getting issues.

Update: I think I got it working wit Meteor.bindEnvironment(

someMethod() {

  const someFunction =  _.throttle(
    Meteor.bindEnvironment(
      () => {
        console.log('hello');
        some other Meteor stuff , like async method calls, etc
      }
    ), 200);
  
  for ( some loop) {
     someFunction();

 }
}

mmmm… having issues with this the function inside he bindEnvironment seems to just complete, no error codes.

I don’t get why you would throttle your own for loop. Could you provide a more complete example?

Also, you are saying you have issues with the code completing and not throwing errors? Isn’t that what you want?

@jorgeer thanks.
It would be nice just to throttle the function the loop is calling. I guess I could write some logic to throttle it in the loop, but I have many scenarios where using _.throttle would be good.

I was after an example of using _.throttle calling a set of nested JS functions and Meteor Methods. Unfortunately providing the exact code would not be possible as it’s part of a a massive system.

Sure, you don’t have to provide the exact code but… I have never heard of throttling a for-loop, which has a specified number of iterations, and you are using a time-based throttle. That will result in a totally unpredictable number of calls being done, and not the number of iterations you are specifying. If you did 100 iterations in the loop for example, you might only get 1 or 2 calls done… I would be very curious to hear the use of this.

If the goal is to just space out a number of operations, then I’d use a task queue or something. You can also space out the operations by using Meteor._sleepForMs() :thinking:

I don’t think _.throttle does what you think it does.

:rofl:I worked out what the problem was… the above code works… the part of the process I could not work out is deep in the code it was meant to be sending an email and I was not receiving it… It was working in my dev environment… just on the Galaxy Dev env it was not arriving and nothing in the logs… ha, ha it was in SPAM!!! So the concept of looping and using _.throttle works.

The pattern is quite common… eg if the loop (could be for forEach, map etc) was making DB updates or external API calls you may want to throttle it. in a pure NodeJS app with async/await I’d use a package like bottleneck … just was trying to get working in Meteor.

Good that you got it working!

However, your implementation still does nothing to hinder bottlenecking… and might harmfully drop data, depending on what you are doing in that for loop. _.throttle does not “slow down” the rate of api calls, it just drops anything in between the timeouts. It does not at all work like the bottleneck package. You would need throttling in front of someMethod for that to work, which Meteor already does over DDP.

Currently, the code above is just nonsensical. You are throttling a loop you have complete control over, and not throttling someMethod which is the one initiating the work. You might as well just drop the for loop and instead call the first and last iteration, it would do the same thing, dropping everything in the middle.

@jorgeer thanks… it’s not actually a for-loop… I had just put it in there for the “simplified” example… it could be a forEach, map etc

I understood (incorrectly) that _.throttle just banked up the calls and did not drop any… just slowed them down but would do 100% of the calls. I thought debounce dropped the calls. So my bad. I am going to see if I can get it working with bottleneck

BTW, is _sleepForMs documented somewhere?

_.throttle and _.debounce are not very useful on the server side. They work when you have an unpredictable number of duplicate calls and you only want a few of the calls to be invoked, like keystrokes or clicks on the client. _.debounce will wait until no calls have been made in [interva], while _.throttle with call the function every [interval] as long as it is receiving calls.

_sleepForMs is only documented in the myths and legends of stack overflow and forum here, but I don’t recommend it, as it will block the main thread. If you want to space out calls over a longer period, without the complexity of a task queue, you could just use Meteor.setTimeout, with a [i x timeout] delay within the loop you are using. So with 200ms x iteration spacing between for example

people.forEach((person, i) =>
  Meteor.setTimeout(() => someFunction(person), i * 200))

Thanks. I actually got the bottleneck approach to work. Basically, I am creating a list of promises and then use bottleneck to limit the calls. So same concept as above and use the rate limiting capability
For example,

const limiter = new Bottleneck({
  maxConcurrent: 1,
  minTime: 333
});

Alright, nice :+1: Glad you got it working

1 Like