From 4b4b27e6a88e02b08af9944c9bce174b1ea40882 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Mon, 7 Mar 2016 19:52:52 +0100 Subject: [PATCH] Handle server disconnects gracefully in the UI Keeps the scope UI's CPU usage low in the browser when the backend is not reachable * dont update app state when repeated errors come in * dont update app state when websocket keeps failing * adjust first loading text, and show icon to draw attention --- client/app/scripts/components/status.js | 4 ++-- client/app/scripts/stores/app-store.js | 12 ++++++++---- client/app/scripts/utils/web-api-utils.js | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/client/app/scripts/components/status.js b/client/app/scripts/components/status.js index 11f2b3078..017b45a1d 100644 --- a/client/app/scripts/components/status.js +++ b/client/app/scripts/components/status.js @@ -12,9 +12,9 @@ export default class Status extends React.Component { classNames += ' status-loading'; showWarningIcon = true; } else if (!this.props.topologiesLoaded) { - text = 'Loading topologies...'; + text = 'Connecting to Scope...'; classNames += ' status-loading'; - showWarningIcon = false; + showWarningIcon = true; } else if (this.props.websocketClosed) { classNames += ' status-loading'; showWarningIcon = true; diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 5b17145c1..c6d6d14e7 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -424,8 +424,10 @@ export class AppStore extends Store { break; case ActionTypes.CLOSE_WEBSOCKET: - websocketClosed = true; - this.__emitChange(); + if (!websocketClosed) { + websocketClosed = true; + this.__emitChange(); + } break; case ActionTypes.DESELECT_NODE: @@ -502,8 +504,10 @@ export class AppStore extends Store { break; case ActionTypes.RECEIVE_ERROR: - errorUrl = payload.errorUrl; - this.__emitChange(); + if (errorUrl !== null) { + errorUrl = payload.errorUrl; + this.__emitChange(); + } break; case ActionTypes.RECEIVE_NODE_DETAILS: diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index fe48b0fac..eb593bec3 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -63,6 +63,8 @@ function createWebsocket(topologyUrl, optionsQuery) { socket.onclose = null; socket.onerror = null; socket.close(); + // onclose() is not called, but that's fine since we're opening a new one + // right away } socket = new WebSocket(wsUrl + topologyUrl @@ -74,9 +76,9 @@ function createWebsocket(topologyUrl, optionsQuery) { socket.onclose = function() { clearTimeout(reconnectTimer); + log('Closing websocket to ' + topologyUrl, socket.readyState); socket = null; closeWebsocket(); - log('Closed websocket to ' + topologyUrl); reconnectTimer = setTimeout(function() { createWebsocket(topologyUrl, optionsQuery); @@ -109,7 +111,7 @@ export function getTopologies(options) { }, TOPOLOGY_INTERVAL); }, error: function(err) { - log('Error in topology request: ' + err); + log('Error in topology request: ' + err.responseText); receiveError(url); topologyTimer = setTimeout(function() { getTopologies(options); @@ -169,7 +171,7 @@ export function getApiDetails() { apiDetailsTimer = setTimeout(getApiDetails, API_INTERVAL); }, error: function(err) { - log('Error in api details request: ' + err); + log('Error in api details request: ' + err.responseText); receiveError(url); apiDetailsTimer = setTimeout(getApiDetails, API_INTERVAL / 2); }