Skip to content

Commit

Permalink
Prevent client polling after shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
jpellizzari committed Mar 21, 2017
1 parent 12f4869 commit 0f86ad1
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 41 deletions.
19 changes: 8 additions & 11 deletions client/app/scripts/actions/app-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
getNodeDetails,
getTopologies,
deletePipe,
stopTopologyPolling,
stopPolling,
teardownWebsockets,
} from '../utils/web-api-utils';
import { getCurrentTopologyUrl } from '../utils/topology-utils';
Expand Down Expand Up @@ -720,20 +720,17 @@ export function toggleTroubleshootingMenu(ev) {

export function changeInstance() {
return (dispatch, getState) => {
dispatch({ type: ActionTypes.CHANGE_INSTANCE });
dispatch({
type: ActionTypes.CHANGE_INSTANCE
});
updateRoute(getState);
const state = getState();
getTopologies(activeTopologyOptionsSelector(state), dispatch);
getNodesDelta(
getCurrentTopologyUrl(state),
activeTopologyOptionsSelector(state),
dispatch,
true // forces websocket teardown and reconnect to new instance
);
};
}

export function shutdown() {
stopTopologyPolling();
stopPolling();
teardownWebsockets();
return {
type: ActionTypes.SHUTDOWN
};
}
9 changes: 5 additions & 4 deletions client/app/scripts/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,18 @@ class App extends React.Component {
window.addEventListener('keyup', this.onKeyUp);

getRouter(this.props.dispatch, this.props.urlState).start({hashbang: true});
if (!this.props.routeSet) {
// dont request topologies when already done via router
getTopologies(this.props.activeTopologyOptions, this.props.dispatch);
if (!this.props.routeSet || process.env.WEAVE_CLOUD) {
// dont request topologies when already done via router.
// If running as a component, always request topologies when the app mounts.
getTopologies(this.props.activeTopologyOptions, this.props.dispatch, true);
}
getApiDetails(this.props.dispatch);
}

componentWillUnmount() {
window.removeEventListener('keypress', this.onKeyPress);
window.removeEventListener('keyup', this.onKeyUp);
shutdown();
this.props.dispatch(shutdown());
}

onKeyUp(ev) {
Expand Down
1 change: 1 addition & 0 deletions client/app/scripts/constants/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const ACTION_TYPES = [
'SET_GRID_MODE',
'CHANGE_INSTANCE',
'TOGGLE_CONTRAST_MODE',
'SHUTDOWN'
];

export default zipObject(ACTION_TYPES, ACTION_TYPES);
5 changes: 5 additions & 0 deletions client/app/scripts/reducers/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,11 @@ export function rootReducer(state = initialState, action) {
return state.set('contrastMode', action.enabled);
}

case ActionTypes.SHUTDOWN: {
state = clearNodes(state);
return state.set('nodesLoaded', false);
}

default: {
return state;
}
Expand Down
69 changes: 43 additions & 26 deletions client/app/scripts/utils/web-api-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ let apiDetailsTimer = 0;
let controlErrorTimer = 0;
let createWebsocketAt = 0;
let firstMessageOnWebsocketAt = 0;
let continuePolling = true;

export function buildOptionsQuery(options) {
if (options) {
Expand Down Expand Up @@ -111,9 +112,11 @@ function createWebsocket(topologyUrl, optionsQuery, dispatch) {
socket = null;
dispatch(closeWebsocket());

reconnectTimer = setTimeout(() => {
createWebsocket(topologyUrl, optionsQuery, dispatch);
}, reconnectTimerInterval);
if (continuePolling) {
reconnectTimer = setTimeout(() => {
createWebsocket(topologyUrl, optionsQuery, dispatch);
}, reconnectTimerInterval);
}
};

socket.onerror = () => {
Expand Down Expand Up @@ -172,35 +175,44 @@ export function getAllNodes(getState, dispatch) {
Promise.resolve());
}

export function getTopologies(options, dispatch) {
export function getTopologies(options, dispatch, initialPoll) {
// Used to resume polling when navigating between pages in Weave Cloud.
continuePolling = initialPoll === true ? true : continuePolling;
clearTimeout(topologyTimer);
const optionsQuery = buildOptionsQuery(options);
const url = `${getApiPath()}/api/topology?${optionsQuery}`;
doRequest({
url,
success: (res) => {
dispatch(receiveTopologies(res));
topologyTimer = setTimeout(() => {
getTopologies(options, dispatch);
}, TOPOLOGY_INTERVAL);
if (continuePolling) {
dispatch(receiveTopologies(res));
topologyTimer = setTimeout(() => {
getTopologies(options, dispatch);
}, TOPOLOGY_INTERVAL);
}
},
error: (err) => {
log(`Error in topology request: ${err.responseText}`);
error: (req) => {
log(`Error in topology request: ${req.responseText}`);
dispatch(receiveError(url));
topologyTimer = setTimeout(() => {
getTopologies(options, dispatch);
}, TOPOLOGY_INTERVAL);
// Only retry in stand-alone mode
if (continuePolling) {
topologyTimer = setTimeout(() => {
getTopologies(options, dispatch);
}, TOPOLOGY_INTERVAL);
}
}
});
}

export function getNodesDelta(topologyUrl, options, dispatch, forceReload) {
export function getNodesDelta(topologyUrl, options, dispatch) {
const optionsQuery = buildOptionsQuery(options);
// Only recreate websocket if url changed or if forced (weave cloud instance reload);
// Check for truthy options and that options have changed.
const isNewOptions = currentOptions && currentOptions !== optionsQuery;
const isNewUrl = topologyUrl && (topologyUrl !== currentUrl || isNewOptions);
if (forceReload || isNewUrl) {
const isNewUrl = topologyUrl !== currentUrl || isNewOptions;
// `topologyUrl` can be undefined initially, so only create a socket if it is truthy
// and no socket exists, or if we get a new url.
if ((topologyUrl && !socket) || (topologyUrl && isNewUrl)) {
createWebsocket(topologyUrl, optionsQuery, dispatch);
currentUrl = topologyUrl;
currentOptions = optionsQuery;
Expand Down Expand Up @@ -250,16 +262,20 @@ export function getApiDetails(dispatch) {
url,
success: (res) => {
dispatch(receiveApiDetails(res));
apiDetailsTimer = setTimeout(() => {
getApiDetails(dispatch);
}, API_INTERVAL);
if (continuePolling) {
apiDetailsTimer = setTimeout(() => {
getApiDetails(dispatch);
}, API_INTERVAL);
}
},
error: (err) => {
log(`Error in api details request: ${err.responseText}`);
error: (req) => {
log(`Error in api details request: ${req.responseText}`);
receiveError(url);
apiDetailsTimer = setTimeout(() => {
getApiDetails(dispatch);
}, API_INTERVAL / 2);
if (continuePolling) {
apiDetailsTimer = setTimeout(() => {
getApiDetails(dispatch);
}, API_INTERVAL / 2);
}
}
});
}
Expand Down Expand Up @@ -353,9 +369,10 @@ export function getPipeStatus(pipeId, dispatch) {
});
}

export function stopTopologyPolling() {
export function stopPolling() {
clearTimeout(apiDetailsTimer);
clearTimeout(topologyTimer);
topologyTimer = 0;
continuePolling = false;
}

export function teardownWebsockets() {
Expand Down

0 comments on commit 0f86ad1

Please sign in to comment.