Skip to content

Commit 4184a1a

Browse files
stephenpluspluscallmehiphop
authored andcommitted
core (stream-router): allow setting maxApiCalls (#1332)
* core (stream-router): allow setting maxApiCalls * move logic to iterator * iterator -> limiter * re-arrange stream-events use * tests. * lint * re-sort tests so overrides dont mess with docs * clean up maxApiCalls property * add system test for bigquery * docs * explain interceptors quirk
1 parent 12d9cdd commit 4184a1a

30 files changed

Lines changed: 679 additions & 269 deletions

File tree

lib/bigquery/dataset.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ Dataset.prototype.delete = function(options, callback) {
279279
* @resource [Tables: list API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/tables/list}
280280
*
281281
* @param {object=} query - Configuration object.
282+
* @param {boolean} query.autoPaginate - Have pagination handled automatically.
283+
* Default: true.
284+
* @param {number} query.maxApiCalls - Maximum number of API calls to make.
282285
* @param {number} query.maxResults - Maximum number of results to return.
283286
* @param {string} query.pageToken - Token returned from a previous call, to
284287
* request the next page of results.

lib/bigquery/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ BigQuery.prototype.dataset = function(id) {
178178
* @param {boolean} query.all - List all datasets, including hidden ones.
179179
* @param {boolean} query.autoPaginate - Have pagination handled automatically.
180180
* Default: true.
181+
* @param {number} query.maxApiCalls - Maximum number of API calls to make.
181182
* @param {number} query.maxResults - Maximum number of results to return.
182183
* @param {string} query.pageToken - Token returned from a previous call, to
183184
* request the next page of results.
@@ -279,6 +280,7 @@ BigQuery.prototype.getDatasets = function(query, callback) {
279280
* project.
280281
* @param {boolean} options.autoPaginate - Have pagination handled
281282
* automatically. Default: true.
283+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
282284
* @param {number=} options.maxResults - Maximum number of results to return.
283285
* @param {string=} options.pageToken - Token returned from a previous call, to
284286
* request the next page of results.
@@ -407,6 +409,7 @@ BigQuery.prototype.job = function(id) {
407409
* @param {string|object} options - A string SQL query or configuration object.
408410
* @param {boolean} options.autoPaginate - Have pagination handled
409411
* automatically. Default: true.
412+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
410413
* @param {number} options.maxResults - Maximum number of results to read.
411414
* @param {string} options.query - A query string, following the BigQuery query
412415
* syntax, of the query to execute.

lib/bigquery/job.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ Job.prototype.cancel = function(callback) {
211211
* @param {object=} options - Configuration object.
212212
* @param {boolean} options.autoPaginate - Have pagination handled
213213
* automatically. Default: true.
214+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
214215
* @param {number} options.maxResults - Maximum number of results to read.
215216
* @param {string} options.pageToken - Page token, returned by a previous call,
216217
* to request the next page of results. Note: This is automatically added to

lib/bigquery/table.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ Table.prototype.export = function(destination, options, callback) {
607607
* @param {object=} options - The configuration object.
608608
* @param {boolean} options.autoPaginate - Have pagination handled
609609
* automatically. Default: true.
610+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
610611
* @param {number} options.maxResults - Maximum number of results to return.
611612
* @param {function} callback - The callback function.
612613
* @param {?error} callback.err - An error returned while making this request

lib/common/stream-router.js

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222

2323
var arrify = require('arrify');
2424
var concat = require('concat-stream');
25-
var split = require('split-array-stream');
25+
var extend = require('extend');
2626
var is = require('is');
27-
var streamEvents = require('stream-events');
28-
var through = require('through2');
27+
var split = require('split-array-stream');
28+
29+
/**
30+
* @type {module:common/util}
31+
* @private
32+
*/
33+
var util = require('./util.js');
2934

3035
/*! Developer Documentation
3136
*
@@ -72,9 +77,10 @@ streamRouter.extend = function(Class, methodNames) {
7277
*/
7378
streamRouter.parseArguments_ = function(args) {
7479
var query;
75-
var callback;
76-
var maxResults = -1;
7780
var autoPaginate = true;
81+
var maxApiCalls = -1;
82+
var maxResults = -1;
83+
var callback;
7884

7985
var firstArgument = args[0];
8086
var lastArgument = args[args.length - 1];
@@ -90,6 +96,8 @@ streamRouter.parseArguments_ = function(args) {
9096
}
9197

9298
if (is.object(query)) {
99+
query = extend(true, {}, query);
100+
93101
// Check if the user only asked for a certain amount of results.
94102
if (is.number(query.maxResults)) {
95103
// `maxResults` is used API-wide.
@@ -99,6 +107,11 @@ streamRouter.parseArguments_ = function(args) {
99107
maxResults = query.pageSize;
100108
}
101109

110+
if (is.number(query.maxApiCalls)) {
111+
maxApiCalls = query.maxApiCalls;
112+
delete query.maxApiCalls;
113+
}
114+
102115
if (callback &&
103116
(maxResults !== -1 || // The user specified a limit.
104117
query.autoPaginate === false)) {
@@ -108,9 +121,10 @@ streamRouter.parseArguments_ = function(args) {
108121

109122
return {
110123
query: query || {},
111-
callback: callback,
124+
autoPaginate: autoPaginate,
125+
maxApiCalls: maxApiCalls,
112126
maxResults: maxResults,
113-
autoPaginate: autoPaginate
127+
callback: callback
114128
};
115129
};
116130

@@ -126,6 +140,7 @@ streamRouter.parseArguments_ = function(args) {
126140
* string in some places.
127141
* @param {function=} parsedArguments.callback - Callback function.
128142
* @param {boolean} parsedArguments.autoPaginate - Auto-pagination enabled.
143+
* @param {boolean} parsedArguments.maxApiCalls - Maximum API calls to make.
129144
* @param {number} parsedArguments.maxResults - Maximum results to return.
130145
* @param {function} originalMethod - The cached method that accepts a callback
131146
* and returns `nextQuery` to receive more results.
@@ -163,6 +178,7 @@ streamRouter.router_ = function(parsedArguments, originalMethod) {
163178
* string in some places.
164179
* @param {function=} parsedArguments.callback - Callback function.
165180
* @param {boolean} parsedArguments.autoPaginate - Auto-pagination enabled.
181+
* @param {boolean} parsedArguments.maxApiCalls - Maximum API calls to make.
166182
* @param {number} parsedArguments.maxResults - Maximum results to return.
167183
* @param {function} originalMethod - The cached method that accepts a callback
168184
* and returns `nextQuery` to receive more results.
@@ -172,12 +188,20 @@ streamRouter.runAsStream_ = function(parsedArguments, originalMethod) {
172188
var query = parsedArguments.query;
173189
var resultsToSend = parsedArguments.maxResults;
174190

175-
var stream = streamEvents(through.obj());
191+
var limiter = util.createLimiter(makeRequest, {
192+
maxApiCalls: parsedArguments.maxApiCalls
193+
});
194+
195+
var stream = limiter.stream;
176196

177197
stream.once('reading', function() {
178-
originalMethod(query, onResultSet);
198+
makeRequest(query);
179199
});
180200

201+
function makeRequest(query) {
202+
originalMethod(query, onResultSet);
203+
}
204+
181205
function onResultSet(err, results, nextQuery) {
182206
if (err) {
183207
stream.destroy(err);
@@ -196,15 +220,15 @@ streamRouter.runAsStream_ = function(parsedArguments, originalMethod) {
196220
}
197221

198222
if (nextQuery && resultsToSend !== 0) {
199-
originalMethod(nextQuery, onResultSet);
223+
limiter.makeRequest(nextQuery);
200224
return;
201225
}
202226

203227
stream.push(null);
204228
});
205229
}
206230

207-
return stream;
231+
return limiter.stream;
208232
};
209233

210234
module.exports = streamRouter;

lib/common/util.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ var request = require('request').defaults({
3333
}
3434
});
3535
var retryRequest = require('retry-request');
36+
var streamEvents = require('stream-events');
3637
var through = require('through2');
3738
var uniq = require('array-uniq');
3839

@@ -545,3 +546,43 @@ function normalizeArguments(globalContext, localConfig, options) {
545546
}
546547

547548
util.normalizeArguments = normalizeArguments;
549+
550+
/**
551+
* Limit requests according to a `maxApiCalls` limit.
552+
*
553+
* @param {function} makeRequestFn - The function that will be called.
554+
* @param {object=} options - Configuration object.
555+
* @param {number} options.maxApiCalls - The maximum number of API calls to
556+
* make.
557+
*/
558+
function createLimiter(makeRequestFn, options) {
559+
var stream = streamEvents(through.obj());
560+
561+
var requestsMade = 0;
562+
var requestsToMake = -1;
563+
564+
options = options || {};
565+
566+
if (is.number(options.maxApiCalls)) {
567+
requestsToMake = options.maxApiCalls;
568+
}
569+
570+
return {
571+
makeRequest: function() {
572+
requestsMade++;
573+
574+
if (requestsToMake >= 0 && requestsMade > requestsToMake) {
575+
stream.push(null);
576+
return;
577+
}
578+
579+
makeRequestFn.apply(null, arguments);
580+
581+
return stream;
582+
},
583+
584+
stream: stream
585+
};
586+
}
587+
588+
util.createLimiter = createLimiter;

lib/compute/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ Compute.prototype.firewall = function(name) {
600600
* (not equal)
601601
* - **`filterString`**: the string to filter to. For string fields, this
602602
* can be a regular expression.
603+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
603604
* @param {number} options.maxResults - Maximum number of addresses to return.
604605
* @param {string} options.pageToken - A previously-returned page token
605606
* representing part of the larger set of results to view.
@@ -716,6 +717,7 @@ Compute.prototype.getAddresses = function(options, callback) {
716717
* (not equal)
717718
* - **`filterString`**: the string to filter to. For string fields, this
718719
* can be a regular expression.
720+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
719721
* @param {number} options.maxResults - Maximum number of addresses to return.
720722
* @param {string} options.pageToken - A previously-returned page token
721723
* representing part of the larger set of results to view.
@@ -834,6 +836,7 @@ Compute.prototype.getAutoscalers = function(options, callback) {
834836
* (not equal)
835837
* - **`filterString`**: the string to filter to. For string fields, this
836838
* can be a regular expression.
839+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
837840
* @param {number} options.maxResults - Maximum number of disks to return.
838841
* @param {string} options.pageToken - A previously-returned page token
839842
* representing part of the larger set of results to view.
@@ -947,6 +950,7 @@ Compute.prototype.getDisks = function(options, callback) {
947950
* (not equal)
948951
* - **`filterString`**: the string to filter to. For string fields, this
949952
* can be a regular expression.
953+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
950954
* @param {number} options.maxResults - Maximum number of instance groups to
951955
* return.
952956
* @param {string} options.pageToken - A previously-returned page token
@@ -1062,6 +1066,7 @@ Compute.prototype.getInstanceGroups = function(options, callback) {
10621066
* (not equal)
10631067
* - **`filterString`**: the string to filter to. For string fields, this
10641068
* can be a regular expression.
1069+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
10651070
* @param {number} options.maxResults - Maximum number of firewalls to return.
10661071
* @param {string} options.pageToken - A previously-returned page token
10671072
* representing part of the larger set of results to view.
@@ -1170,6 +1175,7 @@ Compute.prototype.getFirewalls = function(options, callback) {
11701175
* can be a regular expression.
11711176
* @param {boolean} options.https - List only HTTPs health checks. Default:
11721177
* `false`.
1178+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
11731179
* @param {number} options.maxResults - Maximum number of networks to return.
11741180
* @param {string} options.pageToken - A previously-returned page token
11751181
* representing part of the larger set of results to view.
@@ -1280,6 +1286,7 @@ Compute.prototype.getHealthChecks = function(options, callback) {
12801286
* (not equal)
12811287
* - **`filterString`**: the string to filter to. For string fields, this
12821288
* can be a regular expression.
1289+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
12831290
* @param {number} options.maxResults - Maximum number of networks to return.
12841291
* @param {string} options.pageToken - A previously-returned page token
12851292
* representing part of the larger set of results to view.
@@ -1385,6 +1392,7 @@ Compute.prototype.getNetworks = function(options, callback) {
13851392
* (not equal)
13861393
* - **`filterString`**: the string to filter to. For string fields, this
13871394
* can be a regular expression.
1395+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
13881396
* @param {number} options.maxResults - Maximum number of operations to return.
13891397
* @param {string} options.pageToken - A previously-returned page token
13901398
* representing part of the larger set of results to view.
@@ -1490,6 +1498,7 @@ Compute.prototype.getOperations = function(options, callback) {
14901498
* (not equal)
14911499
* - **`filterString`**: the string to filter to. For string fields, this
14921500
* can be a regular expression.
1501+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
14931502
* @param {number} options.maxResults - Maximum number of instances to return.
14941503
* @param {string} options.pageToken - A previously-returned page token
14951504
* representing part of the larger set of results to view.
@@ -1592,6 +1601,7 @@ Compute.prototype.getRegions = function(options, callback) {
15921601
* (not equal)
15931602
* - **`filterString`**: the string to filter to. For string fields, this
15941603
* can be a regular expression.
1604+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
15951605
* @param {number} options.maxResults - Maximum number of rules to return.
15961606
* @param {string} options.pageToken - A previously-returned page token
15971607
* representing part of the larger set of results to view.
@@ -1696,6 +1706,7 @@ Compute.prototype.getRules = function(options, callback) {
16961706
* (not equal)
16971707
* - **`filterString`**: the string to filter to. For string fields, this
16981708
* can be a regular expression.
1709+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
16991710
* @param {number} options.maxResults - Maximum number of snapshots to return.
17001711
* @param {string} options.pageToken - A previously-returned page token
17011712
* representing part of the larger set of results to view.
@@ -1801,6 +1812,7 @@ Compute.prototype.getServices = function(options, callback) {
18011812
* (not equal)
18021813
* - **`filterString`**: the string to filter to. For string fields, this
18031814
* can be a regular expression.
1815+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
18041816
* @param {number} options.maxResults - Maximum number of snapshots to return.
18051817
* @param {string} options.pageToken - A previously-returned page token
18061818
* representing part of the larger set of results to view.
@@ -1906,6 +1918,7 @@ Compute.prototype.getSnapshots = function(options, callback) {
19061918
* (not equal)
19071919
* - **`filterString`**: the string to filter to. For string fields, this
19081920
* can be a regular expression.
1921+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
19091922
* @param {number} options.maxResults - Maximum number of instances to return.
19101923
* @param {string} options.pageToken - A previously-returned page token
19111924
* representing part of the larger set of results to view.
@@ -2019,6 +2032,7 @@ Compute.prototype.getVMs = function(options, callback) {
20192032
* (not equal)
20202033
* - **`filterString`**: the string to filter to. For string fields, this
20212034
* can be a regular expression.
2035+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
20222036
* @param {number} options.maxResults - Maximum number of instances to return.
20232037
* @param {string} options.pageToken - A previously-returned page token
20242038
* representing part of the larger set of results to view.

lib/compute/instance-group.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ InstanceGroup.prototype.delete = function(callback) {
273273
* (not equal)
274274
* - **`filterString`**: the string to filter to. For string fields, this
275275
* can be a regular expression.
276+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
277+
* @param {number} options.maxResults - Maximum number of VMs to return.
276278
* @param {string} options.pageToken - A previously-returned page token
277279
* representing part of the larger set of results to view.
278280
* @param {boolean} options.running - Only return instances which are running.

lib/compute/network.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ Network.prototype.firewall = function(name) {
278278
* @param {object=} options - Firewall search options.
279279
* @param {boolean} options.autoPaginate - Have pagination handled
280280
* automatically. Default: true.
281+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
281282
* @param {number} options.maxResults - Maximum number of firewalls to return.
282283
* @param {string} options.pageToken - A previously-returned page token
283284
* representing part of the larger set of results to view.

lib/compute/region.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ Region.prototype.createRule = function(name, config, callback) {
282282
* (not equal)
283283
* - **`filterString`**: the string to filter to. For string fields, this
284284
* can be a regular expression.
285+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
285286
* @param {number} options.maxResults - Maximum number of addresses to return.
286287
* @param {string} options.pageToken - A previously-returned page token
287288
* representing part of the larger set of results to view.
@@ -387,6 +388,7 @@ Region.prototype.getAddresses = function(options, callback) {
387388
* (not equal)
388389
* - **`filterString`**: the string to filter to. For string fields, this
389390
* can be a regular expression.
391+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
390392
* @param {number} options.maxResults - Maximum number of operations to return.
391393
* @param {string} options.pageToken - A previously-returned page token
392394
* representing part of the larger set of results to view.
@@ -491,6 +493,7 @@ Region.prototype.getOperations = function(options, callback) {
491493
* (not equal)
492494
* - **`filterString`**: the string to filter to. For string fields, this
493495
* can be a regular expression.
496+
* @param {number} options.maxApiCalls - Maximum number of API calls to make.
494497
* @param {number} options.maxResults - Maximum number of rules to return.
495498
* @param {string} options.pageToken - A previously-returned page token
496499
* representing part of the larger set of results to view.

0 commit comments

Comments
 (0)