ui: Metrics - Don't swallow metrics errors (#9044)

* ui: Make eventsources use http-like errors for stopping

* ui: Don't swallow errors from prometheus, pass them to the ui to handle
This commit is contained in:
John Cowen 2020-10-27 14:51:15 +00:00 committed by GitHub
parent e5b54d9be3
commit a4ec445fb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 28 deletions

View File

@ -7,8 +7,11 @@ const pause = 2000;
export const createErrorBackoff = function(ms = 3000, P = Promise, wait = setTimeout) { export const createErrorBackoff = function(ms = 3000, P = Promise, wait = setTimeout) {
// This expects an ember-data like error // This expects an ember-data like error
return function(err) { return function(err) {
const status = get(err, 'errors.firstObject.status'); // expect and ember-data error or a http-like error (e.statusCode)
let status = get(err, 'errors.firstObject.status') || get(err, 'statusCode');
if (typeof status !== 'undefined') { if (typeof status !== 'undefined') {
// ember-data errors are strings, http errors are numbers
status = status.toString();
switch (true) { switch (true) {
// Any '5xx' (not 500) errors should back off and try again // Any '5xx' (not 500) errors should back off and try again
case status.indexOf('5') === 0 && status.length === 3 && status !== '500': case status.indexOf('5') === 0 && status.length === 3 && status !== '500':

View File

@ -51,8 +51,8 @@ module('Unit | Utility | dom/event-source/blocking', function() {
undefined, undefined,
null, null,
new Error(), new Error(),
{ statusCode: 404 },
{ errors: [] }, { errors: [] },
{ errors: [{ status: 501 }] },
{ errors: [{ status: '401' }] }, { errors: [{ status: '401' }] },
{ errors: [{ status: '500' }] }, { errors: [{ status: '500' }] },
{ errors: [{ status: '5' }] }, { errors: [{ status: '5' }] },
@ -67,6 +67,8 @@ module('Unit | Utility | dom/event-source/blocking', function() {
}); });
test('the 5xx backoff returns a resolve promise on a 5xx (apart from 500)', function(assert) { test('the 5xx backoff returns a resolve promise on a 5xx (apart from 500)', function(assert) {
[ [
{ statusCode: 501 },
{ errors: [{ status: 501 }] },
{ errors: [{ status: '501' }] }, { errors: [{ status: '501' }] },
{ errors: [{ status: '503' }] }, { errors: [{ status: '503' }] },
{ errors: [{ status: '504' }] }, { errors: [{ status: '504' }] },

View File

@ -255,7 +255,7 @@
}, },
fetchStats: function(statsPromises) { fetchStats: function(statsPromises) {
var all = Promise.allSettled(statsPromises). var all = Promise.all(statsPromises).
then(function(results){ then(function(results){
var data = { var data = {
stats: [] stats: []
@ -263,9 +263,7 @@
// Add all non-empty stats // Add all non-empty stats
for (var i = 0; i < statsPromises.length; i++) { for (var i = 0; i < statsPromises.length; i++) {
if (results[i].value) { if (results[i].value) {
data.stats.push(results[i].value); data.stats.push(results[i]);
} else if (results[i].reason) {
console.log("ERROR processing stat", results[i].reason)
} }
} }
return data return data
@ -276,23 +274,21 @@
}, },
fetchStatsGrouped: function(statsPromises) { fetchStatsGrouped: function(statsPromises) {
var all = Promise.allSettled(statsPromises). var all = Promise.all(statsPromises).
then(function(results){ then(function(results){
var data = { var data = {
stats: {} stats: {}
} }
// Add all non-empty stats // Add all non-empty stats
for (var i = 0; i < statsPromises.length; i++) { for (var i = 0; i < statsPromises.length; i++) {
if (results[i].value) { if (results[i]) {
for (var group in results[i].value) { for (var group in results[i]) {
if (!results[i].value.hasOwnProperty(group)) continue; if (!results[i].hasOwnProperty(group)) continue;
if (!data.stats[group]) { if (!data.stats[group]) {
data.stats[group] = [] data.stats[group] = []
} }
data.stats[group].push(results[i].value[group]) data.stats[group].push(results[i][group])
} }
} else if (results[i].reason) {
console.log("ERROR processing stat", results[i].reason)
} }
} }
return data return data
@ -363,11 +359,7 @@
Errors: 'Error responses (with an HTTP response code in the 5xx range) per second.', Errors: 'Error responses (with an HTTP response code in the 5xx range) per second.',
}; };
return this.fetchSeries(q, options) return this.fetchSeries(q, options)
.then(this.reformatSeries(" rps", labelMap), function(xhr){ .then(this.reformatSeries(" rps", labelMap))
// Failure. log to console and return a blank result for now.
console.log('ERROR: failed to fetch requestRate', xhr.responseText)
return emptySeries;
})
}, },
fetchDataRateSeries: function(serviceName, options){ fetchDataRateSeries: function(serviceName, options){
@ -394,11 +386,7 @@
Outbound: 'Outbound data rate (data transmitted) from the network in bits per second.', Outbound: 'Outbound data rate (data transmitted) from the network in bits per second.',
}; };
return this.fetchSeries(q, options) return this.fetchSeries(q, options)
.then(this.reformatSeries("bps", labelMap), function(xhr){ .then(this.reformatSeries("bps", labelMap))
// Failure. log to console and return a blank result for now.
console.log('ERROR: failed to fetch requestRate', xhr.responseText)
return emptySeries;
})
}, },
makeSubject: function(serviceName, type) { makeSubject: function(serviceName, type) {
@ -654,10 +642,6 @@
} }
} }
return data; return data;
}, function(xhr){
// Failure. log to console and return an blank result for now.
console.log("ERROR: failed to fetch stat", label, xhr.responseText)
return {}
}) })
}, },
@ -684,7 +668,9 @@
var o = JSON.parse(xhr.responseText) var o = JSON.parse(xhr.responseText)
resolve(o) resolve(o)
} }
reject(xhr) const e = new Error(xhr.statusText);
e.statusCode = xhr.status;
reject(e);
} }
var url = self.baseURL()+path; var url = self.baseURL()+path;