feat(perf): cloud reporter should retry in case of a timeout
This commit is contained in:
parent
ed7d1cf060
commit
5f5ed06713
@ -80,6 +80,8 @@ var TABLE_FIELDS = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var RETRY_COUNT = 3;
|
||||||
|
|
||||||
class CloudReporter {
|
class CloudReporter {
|
||||||
constructor(benchmarkConfig) {
|
constructor(benchmarkConfig) {
|
||||||
this.tableConfig = createTableConfig(benchmarkConfig);
|
this.tableConfig = createTableConfig(benchmarkConfig);
|
||||||
@ -95,12 +97,12 @@ class CloudReporter {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var flow = browser.driver.controlFlow();
|
var flow = browser.driver.controlFlow();
|
||||||
flow.execute(function() {
|
flow.execute(function() {
|
||||||
return authenticate(self.authConfig).then(function(authClient) {
|
return authenticate(self.authConfig, RETRY_COUNT).then(function(authClient) {
|
||||||
self.authClient = authClient;
|
self.authClient = authClient;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
flow.execute(function() {
|
flow.execute(function() {
|
||||||
return getOrCreateTable(self.authClient, self.tableConfig);
|
return getOrCreateTable(self.authClient, self.tableConfig, RETRY_COUNT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
add(data) {
|
add(data) {
|
||||||
@ -112,40 +114,40 @@ class CloudReporter {
|
|||||||
var allRows = this.allSample.map(function(data) {
|
var allRows = this.allSample.map(function(data) {
|
||||||
return self._convertToTableRow(data, stableSample);
|
return self._convertToTableRow(data, stableSample);
|
||||||
});
|
});
|
||||||
flow.execute(function() {
|
return insertRows(this.authClient, this.tableConfig, allRows, RETRY_COUNT);
|
||||||
return insertRows(self.authClient, self.tableConfig, allRows)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_convertToTableRow(benchpressRow, stableSample) {
|
_convertToTableRow(benchpressRow, stableSample) {
|
||||||
var tableRow = {
|
return {
|
||||||
runId: this.benchmarkConfig.runId,
|
insertId: this.benchmarkConfig.runId+'#'+benchpressRow.index,
|
||||||
benchmarkId: this.benchmarkConfig.id,
|
json: {
|
||||||
index: benchpressRow.index,
|
runId: this.benchmarkConfig.runId,
|
||||||
creationTime: new Date(),
|
benchmarkId: this.benchmarkConfig.id,
|
||||||
browser: this.browserUserAgent,
|
index: benchpressRow.index,
|
||||||
forceGc: benchpressRow.forceGc,
|
creationTime: new Date(),
|
||||||
stable: stableSample.indexOf(benchpressRow) >= 0,
|
browser: this.browserUserAgent,
|
||||||
params: this.benchmarkConfig.params.map(function(param) {
|
forceGc: benchpressRow.forceGc,
|
||||||
if (typeof param.value === 'number') {
|
stable: stableSample.indexOf(benchpressRow) >= 0,
|
||||||
return {
|
params: this.benchmarkConfig.params.map(function(param) {
|
||||||
name: param.name,
|
if (typeof param.value === 'number') {
|
||||||
numvalue: param.value
|
return {
|
||||||
};
|
name: param.name,
|
||||||
} else {
|
numvalue: param.value
|
||||||
return {
|
};
|
||||||
name: param.name,
|
} else {
|
||||||
strvalue: ''+param.value
|
return {
|
||||||
|
name: param.name,
|
||||||
|
strvalue: ''+param.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}),
|
||||||
}),
|
metrics: this.benchmarkConfig.metrics.map(function(metricName, index) {
|
||||||
metrics: this.benchmarkConfig.metrics.map(function(metricName, index) {
|
return {
|
||||||
return {
|
name: metricName,
|
||||||
name: metricName,
|
value: benchpressRow.values[index]
|
||||||
value: benchpressRow.values[index]
|
};
|
||||||
};
|
})
|
||||||
})
|
}
|
||||||
};
|
};
|
||||||
return tableRow;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,14 +162,14 @@ function createTableConfig(benchmarkConfig) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrCreateTable(authClient, tableConfig) {
|
function getOrCreateTable(authClient, tableConfig, retryCount) {
|
||||||
return getTable(authClient, tableConfig).then(null, function(err) {
|
return getTable(authClient, tableConfig, retryCount).then(null, function(err) {
|
||||||
// create the table if it does not exist
|
// create the table if it does not exist
|
||||||
return createTable(authClient, tableConfig);
|
return createTable(authClient, tableConfig, retryCount);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function authenticate(authConfig) {
|
function authenticate(authConfig, retryCount) {
|
||||||
var authClient = new google.auth.JWT(
|
var authClient = new google.auth.JWT(
|
||||||
authConfig['client_email'],
|
authConfig['client_email'],
|
||||||
null,
|
null,
|
||||||
@ -178,12 +180,16 @@ function authenticate(authConfig) {
|
|||||||
|
|
||||||
var defer = webdriver.promise.defer();
|
var defer = webdriver.promise.defer();
|
||||||
authClient.authorize(makeNodeJsResolver(defer));
|
authClient.authorize(makeNodeJsResolver(defer));
|
||||||
return defer.promise.then(function() {
|
var resultPromise = defer.promise.then(function() {
|
||||||
return authClient;
|
return authClient;
|
||||||
});
|
});
|
||||||
|
resultPromise = retryIfNeeded(resultPromise, retryCount, function(newRetryCount) {
|
||||||
|
return authenticate(authConfig, newRetryCount);
|
||||||
|
});
|
||||||
|
return resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTable(authClient, tableConfig) {
|
function getTable(authClient, tableConfig, retryCount) {
|
||||||
// see https://cloud.google.com/bigquery/docs/reference/v2/tables/get
|
// see https://cloud.google.com/bigquery/docs/reference/v2/tables/get
|
||||||
var params = {
|
var params = {
|
||||||
auth: authClient,
|
auth: authClient,
|
||||||
@ -193,10 +199,14 @@ function getTable(authClient, tableConfig) {
|
|||||||
};
|
};
|
||||||
var defer = webdriver.promise.defer();
|
var defer = webdriver.promise.defer();
|
||||||
bigquery.tables.get(params, makeNodeJsResolver(defer));
|
bigquery.tables.get(params, makeNodeJsResolver(defer));
|
||||||
return defer.promise;
|
var resultPromise = defer.promise;
|
||||||
|
resultPromise = retryIfNeeded(resultPromise, retryCount, function(newRetryCount) {
|
||||||
|
return getTable(authClient, tableConfig, newRetryCount);
|
||||||
|
});
|
||||||
|
return resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTable(authClient, tableConfig) {
|
function createTable(authClient, tableConfig, retryCount) {
|
||||||
// see https://cloud.google.com/bigquery/docs/reference/v2/tables
|
// see https://cloud.google.com/bigquery/docs/reference/v2/tables
|
||||||
// see https://cloud.google.com/bigquery/docs/reference/v2/tables#resource
|
// see https://cloud.google.com/bigquery/docs/reference/v2/tables#resource
|
||||||
var params = {
|
var params = {
|
||||||
@ -217,10 +227,23 @@ function createTable(authClient, tableConfig) {
|
|||||||
};
|
};
|
||||||
var defer = webdriver.promise.defer();
|
var defer = webdriver.promise.defer();
|
||||||
bigquery.tables.insert(params, makeNodeJsResolver(defer));
|
bigquery.tables.insert(params, makeNodeJsResolver(defer));
|
||||||
return defer.promise;
|
var resultPromise = defer.promise;
|
||||||
|
resultPromise = retryIfNeeded(resultPromise, retryCount, function(newRetryCount) {
|
||||||
|
return createTable(authClient, tableConfig, newRetryCount);
|
||||||
|
});
|
||||||
|
return resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertRows(authClient, tableConfig, rows) {
|
function insertRows(authClient, tableConfig, rows, retryCount) {
|
||||||
|
// We need to split up the rows in batches as BigQuery
|
||||||
|
// has a size limit on requests.
|
||||||
|
// Note: executing the requests in parallel leads to timeouts sometime...
|
||||||
|
var recurseRows = null;
|
||||||
|
if (rows.length > 10) {
|
||||||
|
recurseRows = rows.slice(10);
|
||||||
|
rows = rows.slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
// see https://cloud.google.com/bigquery/docs/reference/v2/tabledata/insertAll
|
// see https://cloud.google.com/bigquery/docs/reference/v2/tabledata/insertAll
|
||||||
var params = {
|
var params = {
|
||||||
auth: authClient,
|
auth: authClient,
|
||||||
@ -229,22 +252,41 @@ function insertRows(authClient, tableConfig, rows) {
|
|||||||
tableId: tableConfig.table.id,
|
tableId: tableConfig.table.id,
|
||||||
resource: {
|
resource: {
|
||||||
"kind": "bigquery#tableDataInsertAllRequest",
|
"kind": "bigquery#tableDataInsertAllRequest",
|
||||||
"rows": rows.map(function(row) {
|
"rows": rows
|
||||||
return {
|
|
||||||
json: row
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var defer = webdriver.promise.defer();
|
var defer = webdriver.promise.defer();
|
||||||
bigquery.tabledata.insertAll(params, makeNodeJsResolver(defer));
|
bigquery.tabledata.insertAll(params, makeNodeJsResolver(defer));
|
||||||
return defer.promise.then(function(result) {
|
var resultPromise = defer.promise.then(function(result) {
|
||||||
if (result.insertErrors) {
|
if (result.insertErrors) {
|
||||||
throw result.insertErrors.map(function(err) {
|
throw JSON.stringify(result.insertErrors, null, ' ');
|
||||||
return err.errors.map(function(err) {
|
}
|
||||||
return err.message;
|
});
|
||||||
}).join('\n');
|
resultPromise = retryIfNeeded(resultPromise, retryCount, function(newRetryCount) {
|
||||||
}).join('\n');
|
return insertRows(authClient, tableConfig, rows, newRetryCount);
|
||||||
|
});
|
||||||
|
if (recurseRows) {
|
||||||
|
resultPromise = resultPromise.then(function() {
|
||||||
|
return insertRows(authClient, tableConfig, recurseRows, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function retryIfNeeded(promise, retryCount, retryCallback) {
|
||||||
|
if (!retryCount) {
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
return promise.then(null, function(err) {
|
||||||
|
var errStr = err.toString();
|
||||||
|
if (typeof err === 'object') {
|
||||||
|
errStr += JSON.stringify(err, null, ' ');
|
||||||
|
}
|
||||||
|
if (errStr.indexOf('timeout') !== -1) {
|
||||||
|
console.log('Retrying', retryCallback.toString());
|
||||||
|
return retryCallback();
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -252,13 +294,8 @@ function insertRows(authClient, tableConfig, rows) {
|
|||||||
function makeNodeJsResolver(defer) {
|
function makeNodeJsResolver(defer) {
|
||||||
return function(err, result) {
|
return function(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// Normalize errors messages from BigCloud so that they show up nicely
|
// Format errors in a nice way
|
||||||
if (err.errors) {
|
defer.reject(JSON.stringify(err, null, ' '));
|
||||||
err = err.errors.map(function(err) {
|
|
||||||
return err.message;
|
|
||||||
}).join('\n');
|
|
||||||
}
|
|
||||||
defer.reject(err);
|
|
||||||
} else {
|
} else {
|
||||||
defer.fulfill(result);
|
defer.fulfill(result);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user