-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add switchboard artillery target #25
base: main
Are you sure you want to change the base?
Changes from all commits
a635b12
d22d950
bacb33c
27ac736
31e4a24
a9f172c
be2c173
af617cb
b023d1e
533b7f1
c065518
7ae8112
19709a5
0061ffc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
SWITCHBOARD_CLIENT_ID="00000000-0000-4000-0000-000000000000" | ||
SWITCHBOARD_AUTH_TOKEN="SomethingLongAndSecure" | ||
SWITCHBOARD_SENDING_ACCOUNT_ID="00000000-0000-4000-0000-000000000000" | ||
SWITCHBOARD_PROFILE_ID="00000000-0000-4000-0000-000000000000" | ||
BANDWIDTH_CALLBACK_BASIC_AUTH="Base64Encoded(Username:Password)" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Switchboard Artillery Load Testing | ||
|
||
Perform load test against a dry run mode (no calls to 3rd party telecom providers) Switchboard deployment. | ||
|
||
## Setup | ||
|
||
**Stand up Switchboard shard in dry mode** | ||
|
||
TBD | ||
|
||
**Set up billing.clients, sms.sending_accounts, sms.profiles, etc.** | ||
|
||
TBD | ||
|
||
**Set values for Artillery use** | ||
|
||
Copy and update the provided example `.env` | ||
|
||
```sh | ||
cp .env.example .env | ||
vi .env | ||
``` | ||
|
||
## Running | ||
|
||
Artillery scripts can be run locally like this: | ||
|
||
```sh | ||
yarn artillery run \ | ||
--platform=local \ | ||
--environment=staging \ | ||
--dotenv=targets/switchboard/.env \ | ||
targets/switchboard/artillery-scripts/send-message.yaml | ||
``` | ||
|
||
Artillery scripts can be run from AWS Lambda like this: | ||
|
||
Get session for MFA-enabled users. The session returned by the command may be set as the AWS credentials [a few different ways](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). | ||
|
||
```sh | ||
aws sts get-session-token \ | ||
--serial-number arn:aws:iam::123456789012:mfa/user \ | ||
--token-code code-from-token | ||
``` | ||
|
||
Run the script on Lambda: | ||
|
||
```sh | ||
yarn artillery run \ | ||
--platform=aws:lambda \ | ||
--platform-opt region=us-east-1 \ | ||
--platform-opt memory-size=2048 \ | ||
--environment=staging \ | ||
--count=20 \ | ||
--dotenv=targets/switchboard/.env \ | ||
targets/switchboard/artillery-scripts/send-message.yaml | ||
``` | ||
|
||
Lambda limits the file descriptor count [to 1024 per worker](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html). You will need to specify a worker count (`--count`) that will support the maximum concurrent virtual users for the script. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
config: | ||
environments: | ||
staging: | ||
target: "https://staging.switchboard.assemble.live" | ||
phases: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Do we want to treat these like unit tests where these tests all need to pass before a production release occurs? If failing tests are ok, considering you saw good performance up to 500 so far, you could add tests up to 1000? Our Bandwidth rate limit for the registered account is now set to 900, so that feels like a goal to shoot for even if we're not ready to get there yet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of testing on a kind of log scale beyond our current external rate limits so we know our sending rate is artificially limited by policy rather than software performance. So like Aashish mentioned I would set phases for like 100, 200, 400, 800, 1600, 3200 to start with, then doing a bit of a binary search to add new phases so we have a good sense of "max possible performance" within 100 req/s or so. Then we can decide how to do a testing strategy once we know the software perf limits. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Treating stress test performance as part of release acceptance seems like a good idea to me but out of scope for this PR.
This is currently blocked by stress test runner limitations. I encountered file descriptor quota exhaustion on Lambda (see 19709a5) and in attempting to fix that ended up down a rabbit hole debugging other AWS runner issues. |
||
- name: Spike - Spoke Autosending @ 100 | ||
duration: 180 | ||
arrivalRate: 100 | ||
- name: Spike - Spoke Autosending @ 200 | ||
duration: 180 | ||
arrivalRate: 200 | ||
- name: Spike - Spoke Autosending @ 300 | ||
duration: 180 | ||
arrivalRate: 300 | ||
- name: Spike - Spoke Autosending @ 400 | ||
duration: 180 | ||
arrivalRate: 400 | ||
- name: Spike - Spoke Autosending @ 500 | ||
duration: 180 | ||
arrivalRate: 500 | ||
plugins: | ||
metrics-by-endpoint: {} | ||
processor: "../processors/sendMessageProcessor.js" | ||
|
||
scenarios: | ||
- name: "Sending Bandwidth messages" | ||
flow: | ||
# Execute sendMessage mutation | ||
- post: | ||
url: "/sms/graphql" | ||
beforeRequest: generateSendMessageParams | ||
headers: | ||
token: "{{ $processEnvironment.SWITCHBOARD_AUTH_TOKEN }}" | ||
json: | ||
query: | | ||
mutation sendMessage($profileId: UUID!, $to: PhoneNumber!, $body: String!, $contactZipCode: ZipCode, $mediaUrls: [Url], $sendBefore: Datetime!) { | ||
sendMessage(input: {profileId: $profileId, to: $to, body: $body, contactZipCode: $contactZipCode, mediaUrls: $mediaUrls, sendBefore: $sendBefore}) { | ||
outboundMessage { | ||
id | ||
createdAt | ||
} | ||
} | ||
} | ||
variables: | ||
profileId: "{{ $processEnvironment.SWITCHBOARD_PROFILE_ID }}" | ||
to: "{{ toNumber }}" | ||
body: "An SMS from Artillery load test 💣!" | ||
contactZipCode: "11238" | ||
mediaUrls: [] | ||
sendBefore: "2099-01-01" | ||
capture: | ||
- json: "$.data.sendMessage.outboundMessage.id" | ||
as: "messageId" | ||
- json: "$.data.sendMessage.outboundMessage.createdAt" | ||
as: "messageCreatedAt" | ||
|
||
# Give process-grey-route-message a chance to work | ||
- think: 0.2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧠 |
||
|
||
# Receive 'message-sending' DLR | ||
- post: | ||
url: "/hooks/status/{{ $processEnvironment.SWITCHBOARD_SENDING_ACCOUNT_ID }}" | ||
headers: | ||
Authorization: "Basic {{ $processEnvironment.BANDWIDTH_CALLBACK_BASIC_AUTH }}" | ||
json: | ||
- time: "" | ||
type: "message-sending" | ||
to: "+16463893770" | ||
errorCode: "" | ||
description: "" | ||
message: | ||
id: "service-{{ messageId }}" | ||
# owner: "" | ||
# applicationId: "" | ||
time: "{{ messageCreatedAt }}" | ||
segmentCount: 1 | ||
direction: "outbound" | ||
to: | ||
- "+16463893770" | ||
media: [] | ||
text: "An SMS from Artillery load test!" | ||
tag: "v1|{{ messageId }}|{{ messageCreatedAt }}" | ||
|
||
# Receive 'message-delivered' DLR | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Do we want some think time in btwn here before receiving the 2nd DLR or does it not really make a difference? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't make a difference and in practice we have actually seen the second DLR arrive first ( |
||
- post: | ||
url: "/hooks/status/{{ $processEnvironment.SWITCHBOARD_SENDING_ACCOUNT_ID }}" | ||
headers: | ||
Authorization: "Basic {{ $processEnvironment.BANDWIDTH_CALLBACK_BASIC_AUTH }}" | ||
json: | ||
- time: "" | ||
type: "message-delivered" | ||
to: "+16463893770" | ||
errorCode: "" | ||
description: "" | ||
message: | ||
id: "service-{{ messageId }}" | ||
# owner: "" | ||
# applicationId: "" | ||
time: "{{ messageCreatedAt }}" | ||
segmentCount: 1 | ||
direction: "outbound" | ||
to: | ||
- "+16463893770" | ||
media: [] | ||
text: "An SMS from Artillery load test!" | ||
tag: "v1|{{ messageId }}|{{ messageCreatedAt }}" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
function generateSendMessageParams(requestParams, ctx, ee, next) { | ||
const tn = [...Array(10)].map(() => Math.floor(Math.random() * 10)).join(""); | ||
const toNumber = `+1${tn}`; | ||
|
||
ctx.vars.toNumber = toNumber; | ||
|
||
return next(); | ||
} | ||
|
||
module.exports = { generateSendMessageParams }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question (not important): Do you intentionally use
4000
in the middle 😆There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, UUIDv4 always has a
4
at that position