2016-06-27 9 views
1

Ich versuche, REST API-Endpunkte von meiner node.js App zu schlagen, wie folgt:Node.js-API anfordern Grenze mit Anfrage-Versprechen

var people = []; 
for(var i=0; i<n; i++) { 
    //create person 
    people.push(person); 
} 
return Promise.all(people.map(create3APIRequestPromises)); 

wo create3APIRequestPromises etwa folgende ist:

// APIRequestPromise = require('request-promise')(options); 
return Promise.all([APIRequestPromise1, APIRequestPromise2, APIRequestPromise3]); 

Der Code funktioniert für eine kleine Anzahl von Menschen alle richtig, aber wenn ich es zu viel erhöht, beginnt es zu versagen. Ich glaube, dass dieser Fehler von dem Dienst verursacht wird, der die REST-API bereitstellt, die meine Verwendung einschränkt. Also, meine Frage ist, was ist der beste Weg, um die Anzahl der Anfragen zu begrenzen, die ich sage, 10 pro Sekunde.

Ich habe über Node-Rate-Limiter gelesen, aber ich konnte nicht sehen, wie es mit den Versprechen, die ich oben geschrieben habe mit 'Anfrage-Versprechen' (vielleicht ist es mit diesem Modul nicht möglich, so vielleicht passen Sie könnten eine Alternative vorschlagen).

Danke.

+0

Sehen Sie sich https://github.com/charto/cwait an –

Antwort

0

Nun, das ist wirklich eine gute Frage. Ich hatte das gleiche Problem, erkannte, dass niemand es noch gelöst hat, und begann, quota zu implementieren. Es deckt bereits Ihren Anwendungsfall ab.

Erstellen Sie Ihren Manager wie folgt aus:

var quota = require('quota'); 

var manager = new quota.Manager({ 
    backoff: 'timeout' 
}); 

// 10 new requests per second 
manager.addRule({ 
    name: 'main', 
    limit: 10, 
    window: 1000, 
    throttling: 'window-sliding', 
    queueing: 'fifo', 
    resource: 'requests' 
}); 

var quotaServer = new quota.Server(); 
quotaServer.addManager('custom', manager); 

var quotaClient = new quota.Client(quotaServer); 

Dann wird jede Ihrer Anfragen durch diesen Wrapper aufrufen:

var request = require('request-promise'); 

function requestThrottled(options) { 

    var _grant; 

    return quotaClient.requestQuota('custom', {}, { requests: 1 }, { 
     maxWait: 60000 // Each request will be queued for 60 seconds and discarded if it didn't get a slot to be executed until then 
    }) 
      .then(function (grant) { 

       _grant = grant; 

       return request(options); 

      }) 
      .finally(function() { 

       if (_grant) { 
        _grant.dismiss(); 
       } 

      }); 

} 

Sie können Ihre Anfragen stellen nach wie vor:

Promise.all([ 
    requestThrottled(optionsRequest1), 
    requestThrottled(optionsRequest2), 
    requestThrottled(optionsRequest3) 
]) 
0

I denken Sie, dass es in Ihrem Fall besser ist, einfache Zeitauffüllung zwischen Anfragen zu verwenden. Dafür sollten Sie Anfragen in Serien aufteilen und jede Gruppe mit Verzögerung voranstellen. Ich realisiere example. Die Nutzung ist:

// Create timepad function 
var timePad = createTimePad(5, 10e3); // 5 requests each 10 seconds 

// Iterate over people 
return Promise.all(
    people.map(
    (human) => timePad().then(() => create3APIRequestPromises(human)) 
) 
); 

Die Funktion für die Pad-Erstellung:

// Create timepad function where timeout is timeout between calls and series is the maximum 
// number of calls that will be done simultaneously 
function createTimePad(series = 10, timeout = 1000) { 
    var seriesCounter = 0; 
    var delay = 0; 

    return() => { 
    return new Promise((resolve) => { 
     if (--seriesCounter <= 0) { 
     delay += timeout; 
     seriesCounter = series; 
     } 

     setTimeout(resolve, delay); 
    }); 
    }; 
} 

Es ist ziemlich einfach und Split-Anfragen in Gruppen mit unterschiedlicher Größe auf Ihrem Wunsch.