Comparing version 1.1.1 to 1.2.0
@@ -7,2 +7,6 @@ "use strict" | ||
const getNowMillis = () => { | ||
return (new Date()).getTime() | ||
} | ||
class OperationHelper { | ||
@@ -31,2 +35,7 @@ constructor(params) { | ||
// throttling | ||
this.maxRequestsPerSecond = params.maxRequestsPerSecond || 0 | ||
this._timeBetweenRequestsInMilliSeconds = 1 / this.maxRequestsPerSecond * 1000 | ||
this._nextAvailableRequestMillis = getNowMillis() | ||
// set version | ||
@@ -65,2 +74,19 @@ if (typeof(params.version) === 'string') OperationHelper.version = params.version | ||
execute(operation, params, callback) { | ||
let nowMillis = getNowMillis() | ||
if (this.maxRequestsPerSecond === 0) { | ||
return this._execute(operation, params, callback) | ||
} else if (nowMillis >= this._nextAvailableRequestMillis) { | ||
this._nextAvailableRequestMillis = getNowMillis() + this._timeBetweenRequestsInMilliSeconds | ||
return this._execute(operation, params, callback) | ||
} else { | ||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve(this._execute(operation, params, callback)) | ||
}, this._nextAvailableRequestMillis - nowMillis) | ||
this._nextAvailableRequestMillis += this._timeBetweenRequestsInMilliSeconds | ||
}) | ||
} | ||
} | ||
_execute(operation, params, callback) { | ||
if (typeof(operation) === 'undefined') { | ||
@@ -67,0 +93,0 @@ throw new Error('Missing operation parameter') |
@@ -11,2 +11,5 @@ "use strict" | ||
const getNowMillis = () => { | ||
return (new Date()).getTime() | ||
} | ||
@@ -345,3 +348,63 @@ describe('OperationHelper', function () { | ||
}) | ||
context('when throttling is necessary', () => { | ||
let opHelper, startTimeMillis | ||
beforeEach(() => { | ||
opHelper = new OperationHelper(Object.assign({}, baseParams, { | ||
maxRequestsPerSecond: 10 | ||
})) | ||
const buildReqAndResp = () => { | ||
let responseMock = new EventEmitter() | ||
responseMock.setEncoding = sinon.spy() | ||
let requestMock = new EventEmitter() | ||
requestMock.end = () => { | ||
responseMock.emit('data', responseBody) | ||
responseMock.emit('end') | ||
} | ||
return { | ||
req: requestMock, | ||
res: responseMock | ||
} | ||
} | ||
sinon.stub(http, 'request') | ||
const reqRes1 = buildReqAndResp() | ||
const reqRes2 = buildReqAndResp() | ||
const reqRes3 = buildReqAndResp() | ||
http.request.onFirstCall().callsArgWith(1, reqRes1.res).returns(reqRes1.req) | ||
http.request.onSecondCall().callsArgWith(1, reqRes2.res).returns(reqRes2.req) | ||
http.request.onThirdCall().callsArgWith(1, reqRes3.res).returns(reqRes3.req) | ||
sinon.stub(opHelper, 'generateUri').returns('testUri') | ||
const operation = 'ItemSearch' | ||
const params = { | ||
'SearchIndex': 'Books', | ||
'Keywords': 'harry potter', | ||
'ResponseGroup': 'ItemAttributes,Offers' | ||
} | ||
startTimeMillis = getNowMillis() | ||
return Promise.all([ | ||
opHelper.execute(operation, params), | ||
opHelper.execute(operation, params), | ||
opHelper.execute(operation, params) | ||
]) | ||
}) | ||
afterEach(() => { | ||
http.request.restore() | ||
}) | ||
it('should take at least (1 / maxRequestsPerSecond) * (numOperations - 1) seconds to complete', () => { | ||
const durationMillis = getNowMillis() - startTimeMillis | ||
expect(durationMillis).to.be.at.least(200) | ||
expect(durationMillis).to.be.at.most(300) | ||
}) | ||
}) | ||
}) | ||
}) |
{ | ||
"name": "apac", | ||
"description": "Amazon Product Advertising API Client for Node", | ||
"version": "1.1.1", | ||
"version": "1.2.0", | ||
"author": "Dustin McQuay <dmcquay@gmail.com>", | ||
@@ -6,0 +6,0 @@ "scripts": { |
@@ -97,2 +97,19 @@ [![Build Status](https://travis-ci.org/dmcquay/node-apac.svg?branch=master)](https://travis-ci.org/dmcquay/node-apac) | ||
## Throttling / Request Limits | ||
By default, Amazon limits you to one request per second per IP. This limit increases with revenue performance. Learn | ||
more here: http://docs.aws.amazon.com/AWSECommerceService/latest/DG/TroubleshootingApplications.html | ||
To help you ensure you don't exceed the request limit, we provide an automatic throttling feature. By default, apac will | ||
not throttle. To enable throttling, set the maxRequestsPerSecond param when constructing your OperationHelper. | ||
```javascript | ||
var opHelper = new OperationHelper({ | ||
awsId: '[YOUR AWS ID HERE]', | ||
awsSecret: '[YOUR AWS SECRET HERE]', | ||
assocId: '[YOUR ASSOCIATE TAG HERE]', | ||
maxRequestsPerSecond: 1 | ||
}); | ||
``` | ||
## Contributing | ||
@@ -99,0 +116,0 @@ |
37016
683
162