Skip to content
This repository was archived by the owner on Nov 28, 2022. It is now read-only.

Commit a33528e

Browse files
authored
[0.9.0] Fix Load in progress message in performance dashboard (#2281)
* Add LoadRun socket status Remove await from runload fetch Signed-off-by: markcor11 <[email protected]> * return 409 if run in progress Signed-off-by: markcor11 <[email protected]> * Return error message in correct format Signed-off-by: markcor11 <[email protected]> * Return optional err Signed-off-by: markcor11 <[email protected]> * Clear status flag on error Signed-off-by: markcor11 <[email protected]>
1 parent e3db42c commit a33528e

File tree

4 files changed

+55
-36
lines changed

4 files changed

+55
-36
lines changed

src/performance/dashboard/src/components/actions/ActionRunLoad.jsx

+39-19
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
* IBM Corporation - initial API and implementation
1010
******************************************************************************/
1111

12-
import React, { Fragment } from 'react'
13-
import PropTypes from 'prop-types'
12+
import React, { Fragment } from 'react';
13+
import PropTypes from 'prop-types';
1414
import { connect } from 'react-redux';
15-
import IconRun from '@carbon/icons-react/es/play--filled/16'
15+
import queryString from 'query-string';
16+
import IconRun from '@carbon/icons-react/es/play--filled/16';
1617
import IconStop from '@carbon/icons-react/lib/close--outline/16';
1718
import { Button, InlineLoading } from 'carbon-components-react';
1819
import { SocketEvents } from '../../utils/sockets/SocketEvents';
@@ -51,6 +52,11 @@ class ActionRunLoad extends React.Component {
5152
componentDidMount() {
5253
this.props.socket.on(SocketEvents.RUNLOAD_STATUS_CHANGED, data => {
5354
if (data.projectID === this.props.projectID) {
55+
56+
if (queryString.parse(location.search).debugsocket) {
57+
console.log("SocketIO RX: ", data);
58+
}
59+
5460
switch (data.status) {
5561
case 'preparing': {
5662
this.setState({ showModalRunTest: false, loadRunStatus: data, inlineTextLabel: 'Preparing...' });
@@ -62,17 +68,32 @@ class ActionRunLoad extends React.Component {
6268
}
6369
case 'started': {
6470
this.setState({ showModalRunTest: false, loadRunStatus: data, inlineTextLabel: 'Running...' });
71+
this.startCountdown();
6572
break;
6673
}
6774
case 'completed': {
6875
// after receiving a loadrun completion message, wait a bit, then reset the button back to ready
76+
this.setState({ showModalRunTest: false, loadRunStatus: data, inlineTextLabel: 'Completed...' });
77+
let nextData = data;
78+
nextData.status = 'idle';
79+
setTimeout(() => this.setState({ loadRunStatus: nextData }), 3000);
80+
break;
81+
}
82+
case 'cancelling': {
83+
this.setState({ showModalRunTest: false, loadRunStatus: data, inlineTextLabel: 'Cancelling...' });
84+
break;
85+
}
86+
case 'cancelled': {
87+
this.setState({ showModalRunTest: false, loadRunStatus: data, inlineTextLabel: 'Cancelled...' });
6988
let nextData = data;
7089
nextData.status = 'idle';
71-
setTimeout(() => this.setState({ loadRunStatus: nextData }), 2000);
90+
setTimeout(() => this.setState({ loadRunStatus: nextData }), 2000);
7291
break;
7392
}
7493
default: {
75-
this.setState({ loadRunStatus: data });
94+
if (queryString.parse(location.search).debugsocket) {
95+
console.log("Ignoring UISocket RX: ",data);
96+
}
7697
}
7798
}
7899
}
@@ -83,13 +104,13 @@ class ActionRunLoad extends React.Component {
83104
* Ask API to start a new test
84105
*/
85106
handleRunTestDlgStart(descriptionText) {
107+
this.setState({ showModalRunTest: false, loadRunStatus: { status: 'requesting' }, inlineTextLabel: 'Requesting...' });
86108
let instance = this;
87109
this.requestRunLoad(descriptionText).then(function (result) {
88-
instance.setState({ showModalRunTest: false, inlineTextLabel: 'Running...' });
89110
switch (result.status) {
90111
case 202: {
91112
// success - request to start load accepted;
92-
instance.startCountdown();
113+
instance.setState({ loadRunStatus: { status: 'requested' }, inlineTextLabel: 'Requested...' });
93114
break;
94115
}
95116
case 503: {
@@ -112,7 +133,7 @@ class ActionRunLoad extends React.Component {
112133
/**
113134
* Send a post to the metric/runload api to start a new load test.
114135
* An optional description parameter can be provided.
115-
* @param {string} desc
136+
* @param {string} desc
116137
*/
117138
// eslint-disable-next-line class-methods-use-this
118139
async requestRunLoad(desc) {
@@ -128,17 +149,16 @@ class ActionRunLoad extends React.Component {
128149
}
129150

130151
async handleCancelLoad() {
131-
this.setState({ inlineTextLabel: "Cancelling..." });
132152
try {
133153
const response = await fetch(`${AppConstants.API_SERVER}/api/v1/projects/${this.props.projectID}/loadtest/cancel`,
134154
{
135155
method: "POST",
136156
headers: { "Content-Type": "application/json" }
137157
});
138158
const reply = await response;
139-
this.setState({ inlineTextLabel: "Cancelled" });
159+
console.error("Cancel accepted")
140160
} catch (err) {
141-
this.setState({ inlineTextLabel: "Cancel failed" });
161+
console.error("Cancel failed:",err);
142162
}
143163
}
144164

@@ -152,7 +172,7 @@ class ActionRunLoad extends React.Component {
152172

153173
showStartTestNotificationFail(err) {
154174
this.setState(
155-
{ showNotificationRunTestFail: true, notificationError: err },
175+
{ showNotificationRunTestFail: true, notificationError: err, loadRunStatus: { status: '' } },
156176
() => setTimeout(() => this.setState({ showNotificationRunTestFail: false }), 5000)
157177
);
158178
}
@@ -177,10 +197,10 @@ class ActionRunLoad extends React.Component {
177197

178198
render() {
179199
const { showNotificationRunTestFail, loadRunStatus, inlineTextLabel, timeRemaining } = this.state;
180-
let loadRunPreparing = loadRunStatus.status === 'preparing';
181-
let loadRunStarting = loadRunStatus.status === 'starting';
182-
let loadRunActive = loadRunStatus.status === 'started';
183-
let loadRunSuccess = loadRunStatus.status === 'completed';
200+
201+
let loadRunCompleted = loadRunStatus.status === 'completed';
202+
const options = ['preparing', 'starting', 'started', 'completed', 'requesting', 'requested', 'cancelling', 'cancelled']
203+
const showBusy = options.includes(loadRunStatus.status)
184204

185205
let inlineTextLabelFormatted = (timeRemaining !== 0) ? `${inlineTextLabel}${timeRemaining}` : `${inlineTextLabel}`
186206

@@ -189,10 +209,10 @@ class ActionRunLoad extends React.Component {
189209
<RunTestNotificationFail notification={showNotificationRunTestFail} titleMessage={'Request Failed!'} notificationError={this.state.notificationError} />
190210
<div className="ActionRunLoad">
191211
{
192-
(loadRunActive || loadRunSuccess || loadRunPreparing || loadRunStarting) ? (
212+
(showBusy) ? (
193213
<Fragment>
194214
<div style={{ display: 'inline-block', verticalAlign: "middle" }}>
195-
<InlineLoading style={{ marginLeft: '1rem' }} description={inlineTextLabelFormatted} success={loadRunSuccess} />
215+
<InlineLoading style={{ marginLeft: '1rem' }} description={inlineTextLabelFormatted} success={loadRunCompleted} />
196216
</div>
197217
<div style={{ display: 'inline-block', verticalAlign: "middle", float: 'right' }}>
198218
<Button onClick={() => this.handleCancelLoad()} style={{ verticalAlign: "middle", padding: 0, margin: 0 }} renderIcon={IconStop} kind="ghost" small iconDescription="Stop the load run"></Button>
@@ -228,7 +248,7 @@ const ActionRunLoadWithSocket = props => (
228248
ActionRunLoad.propTypes = {
229249
projectID: PropTypes.string.isRequired,
230250
small: PropTypes.bool, // show small button
231-
kind: PropTypes.string // button kind eg: 'ghost'
251+
kind: PropTypes.string // button kind eg: 'ghost'
232252
}
233253

234254

src/pfe/portal/modules/LoadRunner.js

+1
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ module.exports = class LoadRunner {
425425
*/
426426
this.socket.on('disconnect', () => {
427427
log.info('Loadrunner has disconnected')
428+
this.project.loadInProgress = false;
428429
// If this.up is false we're already trying to reconnect
429430
if (this.up) {
430431
// socket.io-client will automatically reconnect and trigger the connect event.

src/pfe/portal/modules/User.js

+3-8
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,6 @@ module.exports = class User {
154154
*/
155155
async runLoad(project, description) {
156156
log.debug("runLoad: project " + project.projectID + " loadInProgress=" + project.loadInProgress);
157-
// If load in progress, throw an error
158-
if (project.loadInProgress) {
159-
throw new LoadRunError("RUN_IN_PROGRESS", `For project ${project.projectID}`);
160-
}
161157
project.loadInProgress = true;
162158
try {
163159
let config = await project.getLoadTestConfig();
@@ -176,12 +172,11 @@ module.exports = class User {
176172
let url = projectProtocol + projectHost + ":" + projectPort + config.path;
177173
config.url = url;
178174
project.loadConfig = config;
179-
log.info(`Running load for project: ${project.projectID} config: ${JSON.stringify(config)}`);
175+
log.info(`Requesting load on project: ${project.projectID} config: ${JSON.stringify(config)}`);
180176
const runLoadResp = await this.loadRunner.runLoad(config, project, description);
181177
return runLoadResp;
182178
} catch (err) {
183179
// Reset run load flag and config in the project, and re-throw the error
184-
project.loadInProgress = false;
185180
project.loadConfig = null;
186181
throw err;
187182
}
@@ -192,15 +187,15 @@ module.exports = class User {
192187
*/
193188
async cancelLoad(project) {
194189
log.debug("cancelLoad: project " + project.projectID + " loadInProgress=" + project.loadInProgress);
195-
190+
this.uiSocket.emit('runloadStatusChanged', { projectID: project.projectID, status: 'cancelling' });
196191
if (project.loadInProgress) {
197192
project.loadInProgress = false;
198193
log.debug("Cancelling load for config: " + JSON.stringify(project.loadConfig));
199-
this.uiSocket.emit('runloadStatusChanged', { projectID: project.projectID, status: 'cancelling' });
200194
let cancelLoadResp = await this.loadRunner.cancelRunLoad(project.loadConfig);
201195
this.uiSocket.emit('runloadStatusChanged', { projectID: project.projectID, status: 'cancelled' });
202196
return cancelLoadResp;
203197
}
198+
this.uiSocket.emit('runloadStatusChanged', { projectID: project.projectID, status: 'cancelled' });
204199
throw new LoadRunError("NO_RUN_IN_PROGRESS", `For project ${project.projectID}`);
205200
}
206201

src/pfe/portal/routes/projects/loadtest.route.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const log = new Logger(__filename);
2727
* 202 on success, 404 if project id does not exist, 400 if options are invalid or a run
2828
* is already in progress, 500 if error
2929
*/
30-
router.post('/api/v1/projects/:id/loadtest', validateReq, async function(req,res){
30+
router.post('/api/v1/projects/:id/loadtest', validateReq, function(req,res){
3131
const user = req.cw_user;
3232
const projectID = req.sanitizeParams('id');
3333
let project = user.projectList.retrieveProject(projectID);
@@ -46,20 +46,23 @@ router.post('/api/v1/projects/:id/loadtest', validateReq, async function(req,res
4646
}
4747

4848
try {
49-
let runLoadResp = await user.runLoad(project, description);
50-
// Response logic completed in ..docker/loadrunner/server.js
51-
res.status(runLoadResp.statusCode).send(runLoadResp.body);
52-
} catch(err) {
53-
log.error(err);
54-
if (err.code == LoadRunError.RUN_IN_PROGRESS) {
55-
res.status(409).send(err.info);
49+
log.info(`LoadTest route: loadInProgres = ${project.loadInProgress}`);
50+
if (project.loadInProgress == undefined || !project.loadInProgress) {
51+
user.runLoad(project, description);
52+
res.status(202).send("");
5653
} else {
57-
res.status(500).send(err.info || err);
54+
const err = new LoadRunError("RUN_IN_PROGRESS", `For project ${project.projectID}`);
55+
res.status(409).send(err.info || err);
5856
}
57+
return;
58+
} catch(err) {
59+
log.error(err);
60+
res.status(500).send(err.info || err);
5961
}
6062
}
6163
});
6264

65+
6366
/**
6467
* API function to cancel load against a given project
6568
* @param req, the request from the UI containing project id

0 commit comments

Comments
 (0)