Skip to content

Commit 26a89f1

Browse files
committed
improve logging and minor updates
1 parent 0a4f3e7 commit 26a89f1

File tree

5 files changed

+60
-38
lines changed

5 files changed

+60
-38
lines changed

cicd/3-app/load-test.template.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ Resources:
3737
awslogs-group: !Ref CloudwatchLogsGroup
3838
awslogs-region: !Ref AWS::Region
3939
awslogs-stream-prefix: !Sub "${AWS::StackName}-task"
40-
Cpu: 1024
40+
Cpu: 2048
4141
ExecutionRoleArn: !Ref ExecutionRole
42-
Memory: 2048
42+
Memory: 4096
4343
NetworkMode: awsvpc
4444
RuntimePlatform:
4545
OperatingSystemFamily: LINUX

load-test/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ COPY ./scripts /scripts
44
WORKDIR /scripts
55
# Override the entry point of the base k6 image
66
ENTRYPOINT []
7-
CMD ["sh", "-c", "k6 run $SCRIPT"]
7+
CMD ["sh", "-c", "k6 run $SCRIPT --quiet"]

load-test/scripts/configuration.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ export const MiniAppType = {
3434

3535
export function getTestOptions(maxUserGoal, rampUpTimeMinutes, highLoadTimeMinutes) {
3636
const maxConcurrentUsers = Math.floor(maxUserGoal / 30);
37-
// set constant VUs to be slightly higher than max concurrent users to account for users taking slightly different
38-
// amounts of time
39-
const constantVUs = Math.floor(maxUserGoal / 25);
4037
return {
4138
scenarios: {
4239
// ramp up to maxConcurrentUsers VUs over rampUpTimeMinutes
@@ -47,24 +44,26 @@ export function getTestOptions(maxUserGoal, rampUpTimeMinutes, highLoadTimeMinut
4744
{duration: `${rampUpTimeMinutes}m`, target: maxConcurrentUsers}
4845
]
4946
},
50-
// have constantVUs VUs do 3 iterations each minute, for a total of highLoadTimeMinutes * 3
47+
// have maxConcurrentUsers VUs do 3 iterations each minute, for a total of highLoadTimeMinutes * 3
5148
// iterations per virutal user.
52-
// Start this after the ramp up time and allow for 1 extra minute in the max duration in case of issues.
49+
// Start this after the ramp up time.
5350
highLoad: {
5451
executor: "per-vu-iterations",
55-
vus: constantVUs,
52+
vus: maxConcurrentUsers,
5653
iterations: 3 * highLoadTimeMinutes, // this is iterations per virtual user
5754
// add a large buffer to max duration to ensure all requests can complete.
58-
maxDuration: `${highLoadTimeMinutes + (Math.floor(highLoadTimeMinutes * 0.5))}m`,
55+
maxDuration: `${highLoadTimeMinutes + (Math.ceil(highLoadTimeMinutes * 0.5))}m`,
5956
startTime: `${rampUpTimeMinutes}m`,
6057
}
6158
},
6259
thresholds: {
6360
exceptions: ["count == 0"],
6461
errors: ["count == 0"],
65-
websocket_session_duration_without_sleep: ["p(95) < 5000"],
62+
timeouts: ["count == 0"],
63+
total_request_time: ["p(95) < 5000"],
6664
long_websocket_sessions: [`count <= ${maxConcurrentUsers}`],
67-
extra_long_websocket_sessions: ["count == 0"]
65+
extra_long_websocket_sessions: ["count == 0"],
66+
dropped_iterations: ["count == 0"]
6867
},
6968
summaryTrendStats: ["avg", "min", "med", "max", "p(90)", "p(95)", "p(98)", "p(99)"],
7069
};

load-test/scripts/loadTest.js

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import http from "k6/http";
33
import { check, sleep } from "k6";
44
import { Counter, Trend } from "k6/metrics";
55
import { helloWorld } from "./sources.js";
6+
import { getRandomId, generateToken } from "./tokenHelpers.js";
67
import {
78
LONG_REQUEST_MS,
89
EXTRA_LONG_REQUEST_MS,
@@ -13,24 +14,24 @@ import {
1314
WEBSOCKET_PARAMS,
1415
getTestOptions
1516
} from "./configuration.js";
16-
import generateToken from "./generateToken.js";
1717

1818
// Change these options to increase the user goal or time to run the test.
1919
export const options = getTestOptions(
20-
/* User goal */ 100,
21-
/* Ramp up time minutes */ 1,
22-
/* High load time minutes */ 1
20+
/* User goal */ 1000,
21+
/* Ramp up time minutes */ 5,
22+
/* High load time minutes */ 10
2323
);
2424

2525
// Change this to test different code
2626
const sourceToTest = helloWorld;
27+
// Timeout is we go greater than the max request time to ensure we stay
28+
// close to our concurrent user goal.
29+
const MAX_REQUEST_TIME_MS = 20000;
2730

2831
const exceptionCounter = new Counter("exceptions");
2932
const errorCounter = new Counter("errors");
30-
const connectToCloseTime = new Trend(
31-
"websocket_session_duration_without_sleep",
32-
true
33-
);
33+
const timeoutCounter = new Counter("timeouts");
34+
const totalRequestTime = new Trend("total_request_time", true);
3435
// websocket sessions > LONG_REQUEST_MS
3536
const longWebsocketSessions = new Counter("long_websocket_sessions");
3637
// websocket sessions > EXTRA_LONG_REQUEST_MS
@@ -42,7 +43,9 @@ function isResultSuccess(result) {
4243
}
4344

4445
export default function () {
45-
const authToken = generateToken(MiniAppType.CONSOLE);
46+
const requestStartTime = Date.now();
47+
const sessionId = getRandomId();
48+
const authToken = generateToken(MiniAppType.CONSOLE, sessionId);
4649
const uploadResult = http.put(
4750
UPLOAD_URL + authToken,
4851
sourceToTest,
@@ -53,41 +56,57 @@ export default function () {
5356

5457
if (isResultSuccess(uploadResult)) {
5558
const res = ws.connect(WEBSOCKET_URL + authToken, WEBSOCKET_PARAMS, (socket) =>
56-
onSocketConnect(socket, Date.now())
59+
onSocketConnect(socket, requestStartTime, Date.now(), sessionId)
5760
);
5861

5962
check(res, { "websocket status is 101": (r) => r && r.status === 101 });
63+
} else {
64+
console.log(`ERROR upload failed for session id ${sessionId}`);
6065
}
6166
}
6267

63-
function onSocketConnect(socket, startTime) {
64-
socket.on("open", () => {});
68+
function onSocketConnect(socket, requestStartTime, websocketStartTime, sessionId) {
69+
socket.on("open", () => {
70+
socket.setTimeout(() => {
71+
console.log(`Triggering TIMEOUT for session id ${sessionId}, request has gone longer than ${MAX_REQUEST_TIME_MS} ms.`);
72+
socket.close();
73+
}, MAX_REQUEST_TIME_MS);
74+
});
6575

6676
socket.on("message", function (data) {
6777
const parsedData = JSON.parse(data);
6878
if (parsedData.type === "EXCEPTION") {
69-
console.log("[EXCEPTION] " + parsedData.value);
79+
console.log(`EXCEPTION for session id ${sessionId} ` + parsedData.value);
7080
exceptionCounter.add(1);
7181
}
7282
});
7383

7484
socket.on("close", () => {
75-
const time = Date.now() - startTime;
76-
connectToCloseTime.add(time);
77-
if (time > LONG_REQUEST_MS) {
78-
longWebsocketSessions.add(1);
79-
}
80-
if (time > EXTRA_LONG_REQUEST_MS) {
81-
extraLongWebsocketSessions.add(1);
85+
const websocketTime = Date.now() - websocketStartTime;
86+
const totalTime = Date.now() - requestStartTime;
87+
if (websocketTime < MAX_REQUEST_TIME_MS) {
88+
// only log requests that didn't time out, as timeouts are a separate metric.
89+
totalRequestTime.add(totalTime);
90+
if (totalTime > EXTRA_LONG_REQUEST_MS) {
91+
console.log(`EXTRA LONG REQUEST Session id ${sessionId} had a request time of ${totalTime} ms.`);
92+
extraLongWebsocketSessions.add(1);
93+
} else if (totalTime > LONG_REQUEST_MS) {
94+
console.log(`LONG REQUEST Session id ${sessionId} had a request time of ${totalTime} ms.`);
95+
longWebsocketSessions.add(1);
96+
}
97+
} else {
98+
console.log(`TIMEOUT detected for session id ${sessionId}`);
99+
timeoutCounter.add(1);
82100
}
83-
const sleepTime = Math.floor(20 - (time / 1000));
101+
102+
const sleepTime = Math.floor((MAX_REQUEST_TIME_MS - totalTime) / 1000);
84103
if (sleepTime > 0) {
85104
sleep(sleepTime);
86105
}
87106
});
88107

89108
socket.on("error", function (e) {
90-
console.log("[ERROR] " + e.error());
109+
console.log(`ERROR on websocket request for session id ${sessionId} ` + e.error());
91110
errorCounter.add(1);
92111
});
93112
}
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,28 @@ import { PRIVATE_KEY } from "./configuration.js";
77

88
// Generate a JWT token for the given mini app type, with random
99
// user id, teacher id and session id. The token has a time to live of 1 minute.
10-
export default function generateToken(miniAppType) {
10+
export function generateToken(miniAppType, sessionId) {
1111
const issuedAtTime = (Date.now() / 1000) - 3;
1212
const expirationTime = issuedAtTime + 63;
1313
const payload = {
1414
iat: issuedAtTime,
1515
iss: "load-test",
1616
exp: expirationTime,
17-
uid: uuidv4(),
17+
uid: getRandomId(),
1818
level_id: "none",
1919
execution_type: "RUN",
2020
mini_app_type: miniAppType,
21-
verified_teachers: uuidv4(),
21+
verified_teachers: getRandomId(),
2222
options: "{}",
23-
sid: uuidv4()
23+
sid: sessionId
2424
};
2525
return encodeAsJWT(payload);
2626
}
2727

28+
export function getRandomId() {
29+
return uuidv4();
30+
}
31+
2832
// Generate a JWT using the HS256 algorithm, which relies on a shared secret
2933
// between the sender and receiver.
3034
// To keep the load test script small we can't use npm packages that do this for us,

0 commit comments

Comments
 (0)