Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I limit Q promise concurrency?

How do I write a method that limits Q promise concurrency?

For instance, I have a method spawnProcess. It returns a Q promise.
I want no more than 5 process spawned at a time, but transparently to the calling code.

What I need to implement is a function with signature

function limitConcurrency(promiseFactory, limit)

that I can call like

spawnProcess = limitConcurrency(spawnProcess, 5);

// use spawnProcess as usual

I already started working on my version, but I wonder if anyone has a concise implementation that I can check against.

like image 603
Dan Abramov Avatar asked Dec 12 '13 14:12

Dan Abramov


2 Answers

I wrote a little library to do this: https://github.com/suprememoocow/qlimit

It's extremely easy to use and is specifically designed to work with Q promises:

var qlimit = require('qlimit');
var limit = qlimit(2); // 2 being the maximum concurrency

// Using the same example as above
return Q.all(items.map(limit(function(item, index, collection) { 
  return performOperationOnItem(item);
}));

It can also be used to limit concurrency to a specific resource, like this:

var qlimit = require('qlimit');
var limit = qlimit(2); // 2 being the maximum concurrency

var fetchSomethingFromEasilyOverwhelmedBackendServer = limit(function(id) {
  // Emulating the backend service
  return Q.delay(1000)
    .thenResolve({ hello: 'world' }); 
});
like image 158
Andrew Newdigate Avatar answered Oct 11 '22 13:10

Andrew Newdigate


I have a library that does this for you https://github.com/ForbesLindesay/throat

You can use it via browserify or download the standalone build from brcdn (https://www.brcdn.org/?module=throat&version=latest) and add it as a script tag.

Then (assuming the Promise constructor is polyfilled or implemented in your environment) you can do:

//remove this line if using standalone build
var throat = require('throat');

function limitConcurrency(promiseFactory, limit) {
  var fn = throat(promiseFactory, limit);
  return function () {
    return Q(fn.apply(this, arguments));
  }
}

You could just call throat(promiseFactory, limit) directly but that would return a promise promise rather than a Q promise.

I also really like using it with array.map.

// only allow 3 parallel downloads
var downloadedItems = Q.all(items.map(throat(download, 3)));
like image 22
ForbesLindesay Avatar answered Oct 11 '22 13:10

ForbesLindesay