# API Maker WebSocket benchmark : 8 vCPU, 32 GB RAM (Linode shared CPU)

> API Maker WebSockets on 8 shared vCPUs, 32 GB (Linode) : 3,662,564 clients connected at once, 9 KB each, 10,939 new clients a second, with memory and outputs.

Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html

<nav class="am-bench-switch" aria-label="WebSocket benchmark servers">
Shared CPU

- [1 vCPU1 GB · 26k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
- [2 vCPU4 GB · 338k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
- [4 vCPU8 GB · 802k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
- [8 vCPU32 GB · 3.66M clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)

Dedicated CPU

- [2 vCPU4 GB · 338k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
- [4 vCPU8 GB · 796k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
- [8 vCPU16 GB · 1.73M clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)

Compare

- [WebSocketsthe answers](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html)
- [All resultsevery server side by side](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html)
- [Scale to N usersone server or many](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html)

</nav>

WebSocket benchmark · Linode (Akamai Cloud) · Shared CPU · 14 October 2026

**8 vCPU, 32 GB RAM : 3,662,564 WebSocket clients connected at once.**

API Maker 4.0.0 on a Linode 32 GB (g6-standard-8) : 8 shared vCPUs and 32 GB of RAM at $192 a month, its MongoDB and Redis on the same machine. A second server opened WebSocket clients, each with both tokens and a subscription of its own, until the memory of the server was full, while autocannon made the calls which notify them : every run 60 seconds, the memory and CPU of every part sampled each second.

Clients connected

3,662,564

the memory was full : 4,478 MB left

Memory per client

8.8KB

API Maker 3.2 · kernel 4.5 · Redis 1.1

New clients / second

10,939

both tokens and a subscription · 24,719 without one

Notification delivered in

0.94ms

p50 at 1,000 a second · p99 6.54 ms

## The server

| | |
|---|---|
| Server | Linode (Akamai Cloud), Linode 32 GB (g6-standard-8), shared cpu, $192 / month |
| CPU | AMD EPYC 7642 48-Core Processor, 8 shared vCPUs (KVM)<br>KVM guest, 1 thread per core · L1d 512 KiB (8 instances) · L2 4 MiB (8 instances) · L3 128 MiB (8 instances) · BogoMIPS 4599.99 |
| Memory | 32 GB (32,095 MB usable), swap 8.5 GB (496 MB of Linode + 8 GB made by the installer) |
| Disk, region | 640 GB SSD, Mumbai, India (ap-west) |
| System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 |
| API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy |
| Settings | the defaults of the installer : one worker thread per vCPU, up to 8,216,320 open files for the service (`LimitNOFILE`), and the sandboxes kept running for the whole run (removeSandboxInactiveSinceMinutes 1440) |
| Network limits | as the installer sets them : 8,216,320 connections tracked by the firewall of Linux (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted (`net.core.somaxconn`). The memory of all its TCP connections together : raised by API Maker as the clients came, to 7.8 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) |
| Databases | MongoDB 8.0.10 (the MongoDB of API Maker, a replica set of one member, in Docker) · Redis 7.0.5 (the Redis of API Maker, in Docker) : on the same server. No other database runs |
| Sandboxes | TypeScript on Node.js 24.21.0 (an image of 404 MB built by API Maker), 2 sandboxes of the account (sandboxCountForAdmin 2, the default) |
| Load generator | Dedicated 64 GB (g6-dedicated-32) : AMD EPYC 7642 48-Core Processor, 32 dedicated vCPUs, Ubuntu 24.04.4 LTS. The WebSocket clients : am_ws_load, a program in Rust made for these benchmarks, a socket and a task per client, from 151 addresses of the load generator. The HTTP calls : Node.js 24.21.0, autocannon 8.0.0 |
| Network | A VLAN of the same data centre, round trip 1.89 ms (ping) |
| Date | 14 October 2026, 03:18 to 04:26 UTC |

Only what the run needs was running : API Maker and its two sandboxes, its MongoDB and its Redis. API Maker was restarted and the swap emptied before the run. How every number was taken : [How the WebSocket benchmarks are made](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/methodology.html). Every server side by side : [All results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html). The APIs of this server : [8 vCPU · 32 GB, API benchmark](https://docs.apimaker.dev/v4/docs/benchmarks/linode-shared-8-vcpu-32gb.html).

## The data

- **The clients** connect to `ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>` : the token of an API user, and the token of a person, a row of the `customers` table of the [benchmark dataset](https://apimaker.dev/json/benchmark_dataset.json) (`https://apimaker.dev/json/benchmark_dataset.json`) made by a DB token generator. API Maker checks both.
- **A subscription** is one `REGISTER` for the custom WebSocket event `order-updates` with a condition of its own : `{ conditionType: 'RESPONSE', criteria: { recipientId: '<the number of the client>' } }`. It is the way [one notification reaches one person](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html).
- **A notification** for one person is 141 bytes ; a row of the dataset told to the clients of a table is 321 bytes.
- **The tables** are the ones of the [API benchmarks](https://docs.apimaker.dev/v4/docs/benchmarks/methodology.html#the-data), in MongoDB : ten rows of customers, ten columns each.

## Results at a glance

**New clients per second**

[Connect : the token of the API user](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#connect-1-token) · 24,511

[Connect : both tokens](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#connect-2-tokens) · 24,719

[Connect with both tokens and subscribe](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#subscribe) · 10,939

[Subscribe to an event with a can user connect code](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect) · the code ran in the server · 9,280

[Subscribe : the code reads the database](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect-database) · the code ran in the sandbox · 4,381

[Subscribe : the code reads the clock](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#can-user-connect-sandbox) · the code ran in the sandbox · 7,741

100 clients at a time connect, are let in and leave, for 60 seconds.

**Notifications per second**

[A notification for one person](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#one-person) · 21,628 calls / second · 21,208

[A broadcast](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#broadcast) · 199 calls / second · 196,995

[Rows inserted in a table](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html#insert) · 1,396 calls / second · 136,942

As many calls as the server takes : what the clients received each second.

## How many clients fit

Clients connect 8,000 a second, level after level, each with both tokens and a subscription of its own ; at each level they wait 30 seconds while the server is sampled (the level the run stops at, 60). The run stopped adding clients at **3,662,564** : the memory of the server was full. 4,129 MB of its 32,096 MB were still counted as available, and Linux had moved 2,537 MB to the swap since the clients began to connect, to make that room : 1,592 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server).

> Diagram : Clients connected and memory used during the run
>
> The run of this server, second after second : the WebSocket clients connected, up to 3,662,564, and the memory the server used, up to 28,325 MB of 32,095 MB.

API Maker · MongoDB of API Maker · Redis · Sandboxes · Linux : its sockets, Docker, the rest · Available

No client

at rest

10,000 clients

connected

250,000 clients

connected

500,000 clients

connected

1,000,000 clients

connected

1,500,000 clients

connected

2,000,000 clients

connected

2,500,000 clients

connected

3,000,000 clients

connected

3,500,000 clients

connected

3,662,564 clients

connected

| Clients | API Maker | Redis | Kernel | MongoDB | Sandboxes | Server, used | Available | Swap | CPU busy |
|---|--:|--:|--:|--:|--:|--:|--:|--:|--:|
| None (at rest) | 121 | 1 | 242 | 124 | 57 | **1,083** | 31,013 | 0 | 0.6 % |
| **10,000** | 163 | 12 | 379 | 162 | 904 | **2,123** | 29,973 | 0 | 1.0 % |
| **250,000** | 938 | 250 | 1,369 | 244 | 906 | **4,009** | 28,087 | 0 | 2.5 % |
| **500,000** | 1,728 | 498 | 2,485 | 243 | 906 | **6,001** | 26,095 | 0 | 6.1 % |
| **1,000,000** | 3,395 | 996 | 4,709 | 243 | 906 | **10,116** | 21,980 | 0 | 11.3 % |
| **1,500,000** | 4,923 | 1,525 | 6,942 | 243 | 906 | **14,082** | 18,014 | 0 | 20.7 % |
| **2,000,000** | 6,600 | 1,990 | 9,174 | 243 | 906 | **18,249** | 13,847 | 0 | 25.6 % |
| **2,500,000** | 8,129 | 2,591 | 11,398 | 243 | 906 | **22,097** | 9,999 | 0 | 26.3 % |
| **3,000,000** | 9,657 | 3,048 | 13,564 | 243 | 905 | **25,904** | 6,191 | 0 | 36.2 % |
| **3,500,000** | 10,594 | 3,505 | 15,732 | 108 | 356 | **27,815** | 4,281 | 1,431 | 46.1 % |
| **3,662,564** | 10,196 | 3,658 | 16,443 | 61 | 245 | **27,618** | 4,478 | 2,691 | 50.6 % |

Memory in MB. API Maker is the resident memory of its process ; Redis is the memory of its data (`used_memory`) ; the kernel of Linux keeps every socket and every tracked connection in its slab ; a container is counted the way `docker stats` counts it. CPU busy is the whole server while the clients wait : the server pings every client once a minute, and each answers.

### Memory when the server is full

With **3,662,564 clients** connected and waiting, of the 32,096 MB of the server :

| Part | At rest, no client | 3,662,564 clients | More |
|---|--:|--:|--:|
| **API Maker** (process) | 121 MB | **10,196 MB** | + 10,075 MB |
| Redis (container) | 3 MB | **3,533 MB** | + 3,530 MB |
| Linux kernel : sockets, tracked connections (slab) | 242 MB | **16,443 MB** | + 16,201 MB |
| MongoDB of API Maker (container) | 124 MB | **61 MB** | − 63 MB |
| Sandboxes (2 containers) | 57 MB | **245 MB** | + 188 MB |
| **Whole server**, used | 1,083 MB | **27,618 MB** | + 26,535 MB |
| Available | 31,013 MB | **4,478 MB** | |
| Swap used | 0 MB | **2,691 MB** | |
| Open files of API Maker | 28 | **3,662,604** | |
| Keys of Redis · channels it listens on | 13 · 5 | **7,325,144 · 3,662,569** | |

MongoDB and the sandboxes grew during the runs before this one (the inserts, the code of the events), not with the clients.

### What a client costs

Between 1,000,000 and 3,000,000 clients (5 levels), each client more cost the server **8.8 KB** :

| Where | Per client | What it is |
|---|--:|---|
| **API Maker** | **3.2 KB** | The client itself : its socket and the one task which reads it, its tokens and what they said, its subscription and the channel it is told on. |
| Linux kernel | 4.5 KB | The TCP socket, and the entry of the connection in the table of the firewall (Docker makes Linux track every connection). |
| Redis | 1.1 KB | The subscription : its key, its place in the list of its condition, and the channel API Maker listens on. |
| **In all** | **8.8 KB** | 118,483 clients per GB of memory. |

Measured over the levels at which nothing was in the swap. The memory the whole server had available went down by 8.1 KB per client : MongoDB, the sandboxes and the cache of files give some back while the clients take theirs.

## One more subscription, and a broadcast to everybody

With 500,000 clients connected, every client sent a second `REGISTER`, for an event without a condition (`announcements`), 8,000 of them a second : 500,000 were taken in 62.5 s. They waited 30 seconds with two subscriptions each, were told 3 broadcasts, one call of the emit event WS API each, and took the subscription back with `UNREGISTER`.

One subscription more

1.2KB

per client : API Maker 0.5 KB · Redis 0.7 KB

A broadcast to 500k clients

5.63s

until the last client read it

Half of them told after

4,256ms

the first after 2,574 ms

Clients told / second

88,778

one call, every client

| Broadcast | Clients told | The call answered after | The first client | Half of them | 99 % of them | The last one | Clients told a second |
|---|--:|--:|--:|--:|--:|--:|--:|
| 1 | 500,000 of 500,000 | 6.69 s | 3,361 ms | 4,932 ms | 6,652 ms | **6,685 ms** | 74,798 |
| 2 | 500,000 of 500,000 | 5.63 s | 2,574 ms | 4,256 ms | 5,603 ms | **5,632 ms** | 88,778 |
| 3 | 500,000 of 500,000 | 6.06 s | 2,284 ms | 3,686 ms | 6,013 ms | **6,058 ms** | 82,536 |

One call of the emit event WS API tells every client : API Maker asks Redis for the clients of the event, publishes the notification for each of them, and the server which holds a client sends it. The times are counted from the moment the call is written to the moment a client reads its notification.

| Memory, 500,000 clients | One subscription each | Two subscriptions each | A subscription more, per client |
|---|--:|--:|--:|
| API Maker | 1,728 MB | 1,974 MB | 0.5 KB |
| Redis (its data) | 498 MB | 851 MB | 0.7 KB |
| Keys of Redis · channels | 1,000,016 · 500,005 | 1,500,017 · 1,000,005 | |
| **Whole server**, less available | | | **1.2 KB** |

## New clients per second

How many clients a second the server lets in : 100 clients at a time connect, are let in and leave, one after the other, for 60 seconds (after 5 seconds which are not counted). It is what a server faces when its clients all come back, after a deployment or a network cut. The times are counted from the start of the TCP connection.

### Connect : the token of the API user

A client connects with `x-am-authorization` alone, is told `CONNECTED`, and leaves. API Maker checks the token of the API user and finds its groups : what every WebSocket client costs before it asks for anything.

Clients / second

24,511

1,472,138 clients in 60 s, 100 at a time

Let in after, p50

2.50ms

connected 2.50 ms · TCP 0.24 ms

Let in after, p99

6.24ms

max 38.6 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **6.7 vCPU** · MongoDB **0.0 vCPU** · whole server busy **89 %** · load generator busy **17 %**

am_ws_load · Connect : the token of the API user · 60 s

```text
$ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>"
Running 60s test @ ws://<server>:38246
100 clients at a time : connect, CONNECTED, leave

┌─────────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
│ Stat        │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
├─────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
│ TCP connect │ 0.18 ms │ 0.24 ms │ 0.52 ms │ 0.98 ms │ 0.28 ms │ 0.3 ms  │ 33.86 ms │
├─────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
│ CONNECTED   │ 1.12 ms │ 2.5 ms  │ 4.54 ms │ 6.24 ms │ 2.61 ms │ 1.16 ms │ 38.59 ms │
├─────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
│ Left        │ 2.33 ms │ 3.86 ms │ 6.54 ms │ 9.34 ms │ 4.05 ms │ 1.55 ms │ 47.04 ms │
└─────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
┌─────────────┬───────┬────────┬────────┬────────┬──────────┬─────────┬───────┐
│ Stat        │ 1%    │ 2.5%   │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min   │
├─────────────┼───────┼────────┼────────┼────────┼──────────┼─────────┼───────┤
│ Clients/Sec │ 8,641 │ 12,298 │ 25,398 │ 26,978 │ 24,535.6 │ 3295.13 │ 8,641 │
└─────────────┴───────┴────────┴────────┴────────┴──────────┴─────────┴───────┘

Time from the start of the connection to each step. Clients counted once per second.
# of samples: 60

1.47M clients let in in 60.06s, 0 refused or lost
```

### Connect : both tokens

A client connects with `x-am-authorization` and `x-am-user-authorization`, is told `CONNECTED`, and leaves. Both tokens are checked : the one of the API user, and the one of a person, made by the DB token generator of the account.

Clients / second

24,719

1,484,603 clients in 60 s, 100 at a time

Let in after, p50

2.53ms

connected 2.53 ms · TCP 0.24 ms

Let in after, p99

4.72ms

max 21.3 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **7.0 vCPU** · MongoDB **0.0 vCPU** · whole server busy **92 %** · load generator busy **20 %**

am_ws_load · Connect : both tokens · 60 s

```text
$ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
Running 60s test @ ws://<server>:38246
100 clients at a time : connect, CONNECTED, leave

┌─────────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
│ Stat        │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
├─────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
│ TCP connect │ 0.18 ms │ 0.24 ms │ 0.47 ms │ 0.58 ms │ 0.27 ms │ 0.17 ms │ 17.74 ms │
├─────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
│ CONNECTED   │ 1.12 ms │ 2.53 ms │ 4.23 ms │ 4.72 ms │ 2.57 ms │ 0.79 ms │ 21.26 ms │
├─────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
│ Left        │ 2.35 ms │ 3.94 ms │ 6.13 ms │ 6.69 ms │ 4.02 ms │ 1 ms    │ 22.66 ms │
└─────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
┌─────────────┬────────┬────────┬────────┬────────┬──────────┬────────┬────────┐
│ Stat        │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg      │ Stdev  │ Min    │
├─────────────┼────────┼────────┼────────┼────────┼──────────┼────────┼────────┤
│ Clients/Sec │ 22,369 │ 22,413 │ 24,828 │ 26,107 │ 24,743.4 │ 803.23 │ 22,369 │
└─────────────┴────────┴────────┴────────┴────────┴──────────┴────────┴────────┘

Time from the start of the connection to each step. Clients counted once per second.
# of samples: 60

1.48M clients let in in 60.06s, 0 refused or lost
```

### Connect with both tokens and subscribe

The whole of what an application does : connect with both tokens, `CONNECTED`, one `REGISTER` for a custom WebSocket event with a condition of its own (`recipientId` : its user id), the answer, then leave. API Maker checks the groups and the auth provider of the event, keeps the subscription in Redis and listens on its channel ; when the client leaves, all of it is taken back.

Clients / second

10,939

656,986 clients in 60 s, 100 at a time

Let in after, p50

7.91ms

connected 2.10 ms · TCP 0.23 ms

Let in after, p99

13.4ms

max 54.7 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **5.2 vCPU** · Redis **0.5 vCPU** · whole server busy **80 %** · load generator busy **9 %**

am_ws_load · Connect with both tokens and subscribe · 60 s

```text
$ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'order-updates'
Running 60s test @ ws://<server>:38246
100 clients at a time : connect, CONNECTED, REGISTER, leave

┌─────────────┬─────────┬─────────┬──────────┬──────────┬─────────┬─────────┬──────────┐
│ Stat        │ 2.5%    │ 50%     │ 97.5%    │ 99%      │ Avg     │ Stdev   │ Max      │
├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
│ TCP connect │ 0.18 ms │ 0.23 ms │ 0.47 ms  │ 0.66 ms  │ 0.26 ms │ 0.23 ms │ 16.18 ms │
├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
│ CONNECTED   │ 0.72 ms │ 2.1 ms  │ 4.35 ms  │ 5.12 ms  │ 2.21 ms │ 1.03 ms │ 22.69 ms │
├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
│ REGISTER    │ 5.05 ms │ 7.91 ms │ 11.64 ms │ 13.37 ms │ 8.08 ms │ 2.11 ms │ 54.66 ms │
├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
│ Left        │ 5.96 ms │ 8.9 ms  │ 13.07 ms │ 14.94 ms │ 9.12 ms │ 2.3 ms  │ 56.42 ms │
└─────────────┴─────────┴─────────┴──────────┴──────────┴─────────┴─────────┴──────────┘
┌─────────────┬───────┬───────┬────────┬────────┬──────────┬─────────┬───────┐
│ Stat        │ 1%    │ 2.5%  │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min   │
├─────────────┼───────┼───────┼────────┼────────┼──────────┼─────────┼───────┤
│ Clients/Sec │ 4,045 │ 9,217 │ 11,172 │ 11,916 │ 10,949.8 │ 1037.85 │ 4,045 │
└─────────────┴───────┴───────┴────────┴────────┴──────────┴─────────┴───────┘

Time from the start of the connection to each step. Clients counted once per second.
# of samples: 60

657k clients let in in 60.06s, 0 refused or lost
```

### Subscribe to an event with a can user connect code

The same, on an event whose *can user connect code* decides who may subscribe : it reads the person of `x-am-user-authorization` from `g.req.auth`. The code ran in the server itself (lean code, QuickJS).

Clients / second

9,280

557,330 clients in 60 s, 100 at a time

Let in after, p50

9.35ms

connected 2.35 ms · TCP 0.23 ms

Let in after, p99

16.9ms

max 60.5 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **5.5 vCPU** · Redis **0.4 vCPU** · whole server busy **83 %** · load generator busy **8 %**

am_ws_load · Subscribe to an event with a can user connect code · 60 s

```text
$ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'checked-token'
Running 60s test @ ws://<server>:38246
100 clients at a time : connect, CONNECTED, REGISTER, leave

┌─────────────┬─────────┬──────────┬──────────┬─────────┬──────────┬─────────┬──────────┐
│ Stat        │ 2.5%    │ 50%      │ 97.5%    │ 99%     │ Avg      │ Stdev   │ Max      │
├─────────────┼─────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ TCP connect │ 0.18 ms │ 0.23 ms  │ 0.46 ms  │ 0.65 ms │ 0.26 ms  │ 0.22 ms │ 13.61 ms │
├─────────────┼─────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ CONNECTED   │ 0.78 ms │ 2.35 ms  │ 5 ms     │ 5.88 ms │ 2.49 ms  │ 1.19 ms │ 28.66 ms │
├─────────────┼─────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ REGISTER    │ 5.72 ms │ 9.35 ms  │ 14.15 ms │ 16.9 ms │ 9.56 ms  │ 2.59 ms │ 60.54 ms │
├─────────────┼─────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ Left        │ 6.8 ms  │ 10.46 ms │ 15.81 ms │ 18.8 ms │ 10.75 ms │ 2.82 ms │ 62.27 ms │
└─────────────┴─────────┴──────────┴──────────┴─────────┴──────────┴─────────┴──────────┘
┌─────────────┬───────┬───────┬───────┬────────┬─────────┬────────┬───────┐
│ Stat        │ 1%    │ 2.5%  │ 50%   │ 97.5%  │ Avg     │ Stdev  │ Min   │
├─────────────┼───────┼───────┼───────┼────────┼─────────┼────────┼───────┤
│ Clients/Sec │ 4,722 │ 5,146 │ 9,294 │ 10,398 │ 9,288.8 │ 999.31 │ 4,722 │
└─────────────┴───────┴───────┴───────┴────────┴─────────┴────────┴───────┘

Time from the start of the connection to each step. Clients counted once per second.
# of samples: 60

557k clients let in in 60.06s, 0 refused or lost
```

### Subscribe : the code reads the database

The same, with a can user connect code which also reads the person from the database (`g.sys.db.getAll` with a `find`) before it answers : one read of MongoDB for every subscription. The code ran in a sandbox of the account.

Clients / second

4,381

263,133 clients in 60 s, 100 at a time

Let in after, p50

21.0ms

connected 2.84 ms · TCP 0.23 ms

Let in after, p99

35.9ms

max 74.3 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **2.6 vCPU** · Redis **0.2 vCPU** · MongoDB **1.3 vCPU** · sandboxes **2.8 vCPU** · whole server busy **92 %** · load generator busy **4 %**

am_ws_load · Subscribe : the code reads the database · 60 s

```text
$ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'checked-database'
Running 60s test @ ws://<server>:38246
100 clients at a time : connect, CONNECTED, REGISTER, leave

┌─────────────┬──────────┬──────────┬──────────┬─────────┬──────────┬─────────┬──────────┐
│ Stat        │ 2.5%     │ 50%      │ 97.5%    │ 99%     │ Avg      │ Stdev   │ Max      │
├─────────────┼──────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ TCP connect │ 0.18 ms  │ 0.23 ms  │ 0.43 ms  │ 0.49 ms │ 0.25 ms  │ 0.12 ms │ 15.08 ms │
├─────────────┼──────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ CONNECTED   │ 1 ms     │ 2.84 ms  │ 7.01 ms  │ 8.19 ms │ 3.14 ms  │ 1.57 ms │ 18.59 ms │
├─────────────┼──────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ REGISTER    │ 12.35 ms │ 21.01 ms │ 32.99 ms │ 35.9 ms │ 21.43 ms │ 5.28 ms │ 74.3 ms  │
├─────────────┼──────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
│ Left        │ 13.51 ms │ 22.37 ms │ 34.56 ms │ 37.5 ms │ 22.81 ms │ 5.39 ms │ 76.1 ms  │
└─────────────┴──────────┴──────────┴──────────┴─────────┴──────────┴─────────┴──────────┘
┌─────────────┬───────┬───────┬───────┬───────┬─────────┬────────┬───────┐
│ Stat        │ 1%    │ 2.5%  │ 50%   │ 97.5% │ Avg     │ Stdev  │ Min   │
├─────────────┼───────┼───────┼───────┼───────┼─────────┼────────┼───────┤
│ Clients/Sec │ 3,972 │ 4,021 │ 4,362 │ 4,869 │ 4,385.6 │ 257.47 │ 3,972 │
└─────────────┴───────┴───────┴───────┴───────┴─────────┴────────┴───────┘

Time from the start of the connection to each step. Clients counted once per second.
# of samples: 60

263k clients let in in 60.06s, 0 refused or lost
```

### Subscribe : the code reads the clock

The same, with a can user connect code which reads the time of the machine (`Date.now()`) : code which is not lean, so API Maker runs it in a sandbox of the account. The code ran in a sandbox of the account.

Clients / second

7,741

464,920 clients in 60 s, 100 at a time

Let in after, p50

11.3ms

connected 2.10 ms · TCP 0.23 ms

Let in after, p99

25.6ms

max 66.5 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **4.6 vCPU** · Redis **0.4 vCPU** · MongoDB **0.0 vCPU** · sandboxes **1.3 vCPU** · whole server busy **88 %** · load generator busy **6 %**

am_ws_load · Subscribe : the code reads the clock · 60 s

```text
$ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'checked-sandbox'
Running 60s test @ ws://<server>:38246
100 clients at a time : connect, CONNECTED, REGISTER, leave

┌─────────────┬─────────┬──────────┬──────────┬─────────┬─────────┬─────────┬──────────┐
│ Stat        │ 2.5%    │ 50%      │ 97.5%    │ 99%     │ Avg     │ Stdev   │ Max      │
├─────────────┼─────────┼──────────┼──────────┼─────────┼─────────┼─────────┼──────────┤
│ TCP connect │ 0.18 ms │ 0.23 ms  │ 0.49 ms  │ 1.09 ms │ 0.27 ms │ 0.34 ms │ 17.23 ms │
├─────────────┼─────────┼──────────┼──────────┼─────────┼─────────┼─────────┼──────────┤
│ CONNECTED   │ 0.85 ms │ 2.1 ms   │ 4.9 ms   │ 6.51 ms │ 2.31 ms │ 1.22 ms │ 32.18 ms │
├─────────────┼─────────┼──────────┼──────────┼─────────┼─────────┼─────────┼──────────┤
│ REGISTER    │ 6.95 ms │ 11.26 ms │ 19.63 ms │ 25.6 ms │ 11.8 ms │ 3.63 ms │ 66.5 ms  │
├─────────────┼─────────┼──────────┼──────────┼─────────┼─────────┼─────────┼──────────┤
│ Left        │ 7.94 ms │ 12.3 ms  │ 21.07 ms │ 28.1 ms │ 12.9 ms │ 3.85 ms │ 70.27 ms │
└─────────────┴─────────┴──────────┴──────────┴─────────┴─────────┴─────────┴──────────┘
┌─────────────┬───────┬───────┬───────┬───────┬─────────┬────────┬───────┐
│ Stat        │ 1%    │ 2.5%  │ 50%   │ 97.5% │ Avg     │ Stdev  │ Min   │
├─────────────┼───────┼───────┼───────┼───────┼─────────┼────────┼───────┤
│ Clients/Sec │ 3,478 │ 4,539 │ 7,910 │ 8,520 │ 7,748.7 │ 897.72 │ 3,478 │
└─────────────┴───────┴───────┴───────┴───────┴─────────┴────────┴───────┘

Time from the start of the connection to each step. Clients counted once per second.
# of samples: 60

465k clients let in in 60.06s, 0 refused or lost
```

## Can user connect code

An event of the WebSocket Events page can carry a *can user connect code* : API Maker runs it for every subscription to the event, with the tokens of the client in `g.req.auth` and the subscription in `g.req.eventData`, and lets the client subscribe when it returns `{ canConnect: true }`. Three codes were measured : one which reads the person of the token, one which also reads the database, one which reads the clock.

**Reads the person of the token**

**Can user connect code of the event checked-token : ran in the server**

```typescript
import * as T from 'types';

async function main(g: T.IAMGlobal) {
    // The person of x-am-user-authorization : only somebody who signed in subscribes, from a country we serve.
    const person = g.req.auth.authAMDB;
    if (!person) return { canConnect: false, errorText: 'Sign in first.' };
    return { canConnect: person.country === 'India', errorText: 'Not available in your country.' };
};
module.exports = main;
```

**Reads the database**

**Can user connect code of the event checked-database : ran in the sandbox**

```typescript
import * as T from 'types';

async function main(g: T.IAMGlobal) {
    const person = g.req.auth.authAMDB;
    if (!person) return { canConnect: false, errorText: 'Sign in first.' };
    // Still a customer ? One read of the database for every subscription.
    const rows = await g.sys.db.getAll({ instance: 'mongodb', database: 'am_bench', collection: 'customers', queryParams: { find: { customer_id: person.customer_id } } });
    return { canConnect: rows.length === 1 && rows[0].country === 'India', errorText: 'Not a customer any more.' };
};
module.exports = main;
```

**Reads the clock**

**Can user connect code of the event checked-sandbox : ran in the sandbox**

```typescript
import * as T from 'types';

async function main(g: T.IAMGlobal) {
    const person = g.req.auth.authAMDB;
    if (!person) return { canConnect: false, errorText: 'Sign in first.' };
    // The time of the machine : this code runs in the sandbox of the account.
    const hour = new Date(Date.now()).getUTCHours();
    return { canConnect: person.country === 'India' && hour >= 0, errorText: 'Not available in your country.' };
};
module.exports = main;
```

| Can user connect code | Runs in | Clients / second | Subscribed after, p50 | p99 | Against no code |
|---|---|--:|--:|--:|--:|
| No code | – | **10,939** | 7.91 ms | 13.4 ms | – |
| Reads the person of the token | the server (QuickJS) | **9,280** | 9.35 ms | 16.9 ms | 15 % fewer |
| Reads the person from the database | a sandbox of the account | **4,381** | 21.0 ms | 35.9 ms | 60 % fewer |
| Reads the clock | a sandbox of the account | **7,741** | 11.3 ms | 25.6 ms | 29 % fewer |

Lean code (it only reads what it is handed) runs in the server itself, with QuickJS, on the thread which serves the client. Code which needs more runs in a sandbox of the account : every subscription is then a round trip to the sandbox.

## Notifications

With 10,000 clients connected, autocannon makes the HTTP calls which notify them, for 60 seconds, and the clients count what they receive and how late. Each kind of notification is measured twice : at a pace far under what the server takes, which shows how long a notification takes, and with no pace, which shows how many a second the server tells. *Delivery* is the time from the moment autocannon writes the request to the moment the client reads the notification : the HTTP call, API Maker, Redis, and the WebSocket.

### A notification for one person

autocannon calls the [emit event WS API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-emit-event-ws-api.html) with both tokens ; every call names another one of the 10,000 connected clients (`recipientId`), which is the only one told. The clients measure how long each notification took from the moment its request was written.

**1,000 calls a second**

Calls / second (paced)

1,000

60,000 calls in 60 s, 10 connections

Notifications / second

983

60,010 received by 10,000 clients

Delivery p50

0.94ms

average 1.14 ms

Delivery p99

6.54ms

max 21.3 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **0.4 vCPU** · Redis **0.1 vCPU** · whole server busy **7 %** · load generator busy **1 %**

    autocannon · A notification for one person, 1,000 a second

    ```text
    $ autocannon -c 10 -d 60 -R 1000 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    10 connections

    ┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%   │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤
    │ Latency │ 0 ms │ 1 ms │ 7 ms  │ 10 ms │ 1.25 ms │ 1.92 ms │ 23 ms │
    └─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘
    ┌───────────┬────────┬────────┬────────┬────────┬────────┬───────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Req/Sec   │ 995    │ 998    │ 1,000  │ 1,003  │ 1,000  │ 1.26  │ 995    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Bytes/Sec │ 355 kB │ 356 kB │ 357 kB │ 358 kB │ 357 kB │ 436 B │ 355 kB │
    └───────────┴────────┴────────┴────────┴────────┴────────┴───────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 0            │
    ├────────────┼──────────────┤
    │ 25         │ 0            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 3            │
    ├────────────┼──────────────┤
    │ 97.5       │ 7            │
    ├────────────┼──────────────┤
    │ 99         │ 10           │
    ├────────────┼──────────────┤
    │ 99.9       │ 17           │
    ├────────────┼──────────────┤
    │ 99.99      │ 20           │
    ├────────────┼──────────────┤
    │ 99.999     │ 23           │
    └────────────┴──────────────┘

    61k requests in 60.03s, 21.4 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.04s

    ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 0.71 ms │ 0.94 ms │ 3.86 ms │ 6.54 ms │ 1.14 ms │ 1.08 ms │ 21.25 ms │
    └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬───────┬───────┬───────┬────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg   │ Stdev  │ Min │
    ├───────────┼────┼──────┼───────┼───────┼───────┼────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 1,000 │ 1,000 │ 951.8 │ 213.87 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴───────┴────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    60k notifications received in 64.04s (60,010 of 60,000 expected), 10.7 MB read
    ```

**As many as the server takes**

Calls / second

21,628

1,297,651 calls in 60 s, 100 connections

Notifications / second

21,208

1,297,750 received by 10,000 clients

Delivery p50

4.33ms

average 4.47 ms

Delivery p99

7.77ms

max 45.8 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **6.4 vCPU** · Redis **0.3 vCPU** · whole server busy **88 %** · load generator busy **11 %**

    autocannon · A notification for one person, as many as the server takes

    ```text
    $ autocannon -c 100 -d 60 -w 10 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    100 connections
    10 workers

    ┌─────────┬──────┬──────┬───────┬──────┬────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg    │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼────────┼─────────┼───────┤
    │ Latency │ 2 ms │ 4 ms │ 6 ms  │ 8 ms │ 4.1 ms │ 1.36 ms │ 52 ms │
    └─────────┴──────┴──────┴───────┴──────┴────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬───────────┬──────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤
    │ Req/Sec   │ 10,303  │ 12,919  │ 21,983  │ 23,727  │ 21,627.47 │ 2,180.19 │ 10,297  │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤
    │ Bytes/Sec │ 3.68 MB │ 4.61 MB │ 7.85 MB │ 8.47 MB │ 7.72 MB   │ 778 kB   │ 3.68 MB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴───────────┴──────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 2            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 3            │
    ├────────────┼──────────────┤
    │ 25         │ 3            │
    ├────────────┼──────────────┤
    │ 50         │ 4            │
    ├────────────┼──────────────┤
    │ 75         │ 5            │
    ├────────────┼──────────────┤
    │ 90         │ 5            │
    ├────────────┼──────────────┤
    │ 97.5       │ 6            │
    ├────────────┼──────────────┤
    │ 99         │ 8            │
    ├────────────┼──────────────┤
    │ 99.9       │ 19           │
    ├────────────┼──────────────┤
    │ 99.99      │ 29           │
    ├────────────┼──────────────┤
    │ 99.999     │ 39           │
    └────────────┴──────────────┘

    1298k requests in 60.01s, 463 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.20s

    ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 2.76 ms │ 4.33 ms │ 6.72 ms │ 7.77 ms │ 4.47 ms │ 1.31 ms │ 45.76 ms │
    └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬────────┬────────┬──────────┬─────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min │
    ├───────────┼────┼──────┼────────┼────────┼──────────┼─────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 21,941 │ 23,650 │ 20,741.1 │ 4670.40 │ 0   │
    └───────────┴────┴──────┴────────┴────────┴──────────┴─────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    1.30M notifications received in 64.20s (1,297,750 of 1,297,651 expected), 232.4 MB read
    ```

### A broadcast

1,000 more clients subscribe to an event without a condition : every call of the emit event WS API reaches all 1,000 of them.

**5 calls a second**

Calls / second (paced)

5

300 calls in 60 s, 1 connection

Notifications / second

4,994

300,000 received by 1,000 clients

Delivery p50

8.70ms

average 9.36 ms

Delivery p99

19.9ms

max 43.6 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · whole server busy **3 %** · load generator busy **4 %**

    autocannon · A broadcast to 1,000 clients, 5 a second

    ```text
    $ autocannon -c 1 -d 60 -R 5 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    1 connections

    ┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%   │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤
    │ Latency │ 1 ms │ 8 ms │ 18 ms │ 20 ms │ 8.77 ms │ 5.22 ms │ 44 ms │
    └─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘
    ┌───────────┬────────┬────────┬────────┬────────┬────────┬───────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Req/Sec   │ 5      │ 5      │ 5      │ 5      │ 5      │ 0     │ 5      │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Bytes/Sec │ 1.8 kB │ 1.8 kB │ 1.8 kB │ 1.8 kB │ 1.8 kB │ 0 B   │ 1.8 kB │
    └───────────┴────────┴────────┴────────┴────────┴────────┴───────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 1            │
    ├────────────┼──────────────┤
    │ 2.5        │ 1            │
    ├────────────┼──────────────┤
    │ 10         │ 2            │
    ├────────────┼──────────────┤
    │ 25         │ 4            │
    ├────────────┼──────────────┤
    │ 50         │ 8            │
    ├────────────┼──────────────┤
    │ 75         │ 13           │
    ├────────────┼──────────────┤
    │ 90         │ 15           │
    ├────────────┼──────────────┤
    │ 97.5       │ 18           │
    ├────────────┼──────────────┤
    │ 99         │ 20           │
    ├────────────┼──────────────┤
    │ 99.9       │ 40           │
    ├────────────┼──────────────┤
    │ 99.99      │ 44           │
    ├────────────┼──────────────┤
    │ 99.999     │ 44           │
    └────────────┴──────────────┘

    305 requests in 60.07s, 108 kB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    1,000 clients subscribed, 63.08s

    ┌──────────┬─────────┬────────┬──────────┬──────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%    │ 97.5%    │ 99%      │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 4.58 ms │ 8.7 ms │ 17.44 ms │ 19.94 ms │ 9.36 ms │ 3.71 ms │ 43.62 ms │
    └──────────┴─────────┴────────┴──────────┴──────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬───────┬───────┬─────────┬────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg     │ Stdev  │ Min │
    ├───────────┼────┼──────┼───────┼───────┼─────────┼────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 5,000 │ 5,000 │ 4,836.1 │ 890.39 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴─────────┴────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 63

    300k notifications received in 63.08s (300,000 of 300,000 expected), 46.0 MB read
    ```

**As many as the server takes**

Calls / second

199

11,947 calls in 60 s, 10 connections

Notifications / second

196,995

11,957,000 received by 1,000 clients

Delivery p50

40.4ms

average 41.0 ms

Delivery p99

69.4ms

max 152 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **6.2 vCPU** · Redis **0.3 vCPU** · whole server busy **86 %** · load generator busy **14 %**

    autocannon · A broadcast to 1,000 clients, as many as the server takes

    ```text
    $ autocannon -c 10 -d 60 -w 10 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    10 connections
    10 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev    │ Max    │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
    │ Latency │ 32 ms │ 49 ms │ 71 ms │ 77 ms │ 49.65 ms │ 10.48 ms │ 281 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 149     │ 155     │ 196     │ 245     │ 199.12  │ 19.47   │ 149     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 53.7 kB │ 55.8 kB │ 70.6 kB │ 88.3 kB │ 71.7 kB │ 7.01 kB │ 53.6 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 18           │
    ├────────────┼──────────────┤
    │ 0.01       │ 18           │
    ├────────────┼──────────────┤
    │ 0.1        │ 23           │
    ├────────────┼──────────────┤
    │ 1          │ 28           │
    ├────────────┼──────────────┤
    │ 2.5        │ 32           │
    ├────────────┼──────────────┤
    │ 10         │ 38           │
    ├────────────┼──────────────┤
    │ 25         │ 43           │
    ├────────────┼──────────────┤
    │ 50         │ 49           │
    ├────────────┼──────────────┤
    │ 75         │ 55           │
    ├────────────┼──────────────┤
    │ 90         │ 62           │
    ├────────────┼──────────────┤
    │ 97.5       │ 71           │
    ├────────────┼──────────────┤
    │ 99         │ 77           │
    ├────────────┼──────────────┤
    │ 99.9       │ 114          │
    ├────────────┼──────────────┤
    │ 99.99      │ 267          │
    ├────────────┼──────────────┤
    │ 99.999     │ 281          │
    └────────────┴──────────────┘

    12k requests in 60.01s, 4.3 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    1,000 clients subscribed, 63.70s

    ┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬───────────┐
    │ Stat     │ 2.5%     │ 50%      │ 97.5%    │ 99%      │ Avg      │ Stdev    │ Max       │
    ├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼───────────┤
    │ Delivery │ 22.45 ms │ 40.38 ms │ 62.82 ms │ 69.38 ms │ 40.99 ms │ 10.27 ms │ 152.06 ms │
    └──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴───────────┘
    ┌───────────┬────┬──────┬─────────┬─────────┬───────────┬──────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min │
    ├───────────┼────┼──────┼─────────┼─────────┼───────────┼──────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 192,532 │ 245,262 │ 191,659.5 │ 41318.09 │ 0   │
    └───────────┴────┴──────┴─────────┴─────────┴───────────┴──────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    11.96M notifications received in 63.70s (11,957,000 of 11,947,000 expected), 1834.6 MB read
    ```

### Rows inserted in a table

100 clients subscribe to the insert API of a table (`SCHEMA_POST_BULK_INSERT` on `inserts_public`, `getEventData: true`) ; autocannon inserts rows of the [dataset](https://apimaker.dev/json/benchmark_dataset.json) through the [insert API](https://docs.apimaker.dev/v4/docs/apis-all/schema-apis/auto-generated-schema-based-save-single-or-multiple-api.html), and every row saved is told to each of the 100 clients, with its columns.

**50 calls a second**

Calls / second (paced)

50

3,000 calls in 60 s, 10 connections

Notifications / second

4,930

301,000 received by 100 clients

Delivery p50

13.4ms

average 14.1 ms

Delivery p99

35.5ms

max 50.0 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **0.2 vCPU** · Redis **0.0 vCPU** · MongoDB **0.1 vCPU** · whole server busy **4 %** · load generator busy **5 %**

    autocannon · Inserts told to 100 clients, 50 inserts a second

    ```text
    $ autocannon -c 10 -d 60 -R 50 -l -m POST -b '{"customer_id":1,"first_name":"BENCH","last_name":"INSERT","phone":<now>,"last_update":"2006-02-15T04:34:00.330Z","pincode":111111,"shipping_id":2,"dob":"2022-10-30T03:25:03.000Z","country":"India"}' -H "content-type: application/json" "http://<server>:38246/api/schema/bench/mongodb/am_bench/inserts_public/save-single-or-multiple"
    Running 60s test @ http://<server>:38246/api/schema/bench/mongodb/am_bench/inserts_public/save-single-or-multiple
    10 connections

    ┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%   │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤
    │ Latency │ 1 ms │ 4 ms │ 15 ms │ 20 ms │ 5.14 ms │ 3.79 ms │ 31 ms │
    └─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
    │ Req/Sec   │ 50      │ 50      │ 50      │ 50      │ 50      │ 0      │ 50      │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
    │ Bytes/Sec │ 30.2 kB │ 30.2 kB │ 30.3 kB │ 30.3 kB │ 30.2 kB │ 4.43 B │ 30.2 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 1            │
    ├────────────┼──────────────┤
    │ 2.5        │ 1            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 2            │
    ├────────────┼──────────────┤
    │ 50         │ 4            │
    ├────────────┼──────────────┤
    │ 75         │ 7            │
    ├────────────┼──────────────┤
    │ 90         │ 9            │
    ├────────────┼──────────────┤
    │ 97.5       │ 15           │
    ├────────────┼──────────────┤
    │ 99         │ 20           │
    ├────────────┼──────────────┤
    │ 99.9       │ 27           │
    ├────────────┼──────────────┤
    │ 99.99      │ 30           │
    ├────────────┼──────────────┤
    │ 99.999     │ 31           │
    └────────────┴──────────────┘

    3k requests in 60.04s, 1.81 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    100 clients subscribed, 64.06s

    ┌──────────┬─────────┬──────────┬──────────┬──────────┬──────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%      │ 97.5%    │ 99%      │ Avg      │ Stdev   │ Max      │
    ├──────────┼─────────┼──────────┼──────────┼──────────┼──────────┼─────────┼──────────┤
    │ Delivery │ 7.55 ms │ 13.42 ms │ 25.98 ms │ 35.55 ms │ 14.13 ms │ 4.86 ms │ 50.05 ms │
    └──────────┴─────────┴──────────┴──────────┴──────────┴──────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬───────┬───────┬─────────┬─────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg     │ Stdev   │ Min │
    ├───────────┼────┼──────┼───────┼───────┼─────────┼─────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 5,000 │ 5,000 │ 4,774.2 │ 1006.74 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴─────────┴─────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    301k notifications received in 64.06s (301,000 of 300,000 expected), 94.4 MB read
    ```

**As many as the server takes**

Calls / second

1,396

83,727 calls in 60 s, 100 connections

Notifications / second

136,942

8,382,200 received by 100 clients

Delivery p50

246ms

average 248 ms

Delivery p99

332ms

max 538 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **4.8 vCPU** · Redis **0.2 vCPU** · MongoDB **1.2 vCPU** · whole server busy **85 %** · load generator busy **9 %**

    autocannon · Inserts told to 100 clients, as many as the server takes

    ```text
    $ autocannon -c 100 -d 60 -w 10 -l -m POST -b '{"customer_id":1,"first_name":"BENCH","last_name":"INSERT","phone":<now>,"last_update":"2006-02-15T04:34:00.330Z","pincode":111111,"shipping_id":2,"dob":"2022-10-30T03:25:03.000Z","country":"India"}' -H "content-type: application/json" "http://<server>:38246/api/schema/bench/mongodb/am_bench/inserts_public/save-single-or-multiple"
    Running 60s test @ http://<server>:38246/api/schema/bench/mongodb/am_bench/inserts_public/save-single-or-multiple
    100 connections
    10 workers

    ┌─────────┬───────┬───────┬────────┬────────┬─────────┬──────────┬────────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5%  │ 99%    │ Avg     │ Stdev    │ Max    │
    ├─────────┼───────┼───────┼────────┼────────┼─────────┼──────────┼────────┤
    │ Latency │ 46 ms │ 70 ms │ 101 ms │ 111 ms │ 71.1 ms │ 14.23 ms │ 218 ms │
    └─────────┴───────┴───────┴────────┴────────┴─────────┴──────────┴────────┘
    ┌───────────┬────────┬────────┬────────┬────────┬──────────┬─────────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼──────────┼─────────┼────────┤
    │ Req/Sec   │ 969    │ 1,221  │ 1,386  │ 1,637  │ 1,395.45 │ 131.33  │ 969    │
    ├───────────┼────────┼────────┼────────┼────────┼──────────┼─────────┼────────┤
    │ Bytes/Sec │ 586 kB │ 739 kB │ 839 kB │ 991 kB │ 844 kB   │ 79.4 kB │ 586 kB │
    └───────────┴────────┴────────┴────────┴────────┴──────────┴─────────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 8            │
    ├────────────┼──────────────┤
    │ 0.01       │ 11           │
    ├────────────┼──────────────┤
    │ 0.1        │ 27           │
    ├────────────┼──────────────┤
    │ 1          │ 42           │
    ├────────────┼──────────────┤
    │ 2.5        │ 46           │
    ├────────────┼──────────────┤
    │ 10         │ 55           │
    ├────────────┼──────────────┤
    │ 25         │ 62           │
    ├────────────┼──────────────┤
    │ 50         │ 70           │
    ├────────────┼──────────────┤
    │ 75         │ 79           │
    ├────────────┼──────────────┤
    │ 90         │ 88           │
    ├────────────┼──────────────┤
    │ 97.5       │ 101          │
    ├────────────┼──────────────┤
    │ 99         │ 111          │
    ├────────────┼──────────────┤
    │ 99.9       │ 155          │
    ├────────────┼──────────────┤
    │ 99.99      │ 185          │
    ├────────────┼──────────────┤
    │ 99.999     │ 218          │
    └────────────┴──────────────┘

    84k requests in 60.02s, 50.6 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    100 clients subscribed, 64.22s

    ┌──────────┬───────────┬───────────┬───────────┬───────────┬───────────┬──────────┬───────────┐
    │ Stat     │ 2.5%      │ 50%       │ 97.5%     │ 99%       │ Avg       │ Stdev    │ Max       │
    ├──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────┼───────────┤
    │ Delivery │ 196.48 ms │ 246.27 ms │ 308.48 ms │ 332.03 ms │ 247.98 ms │ 33.43 ms │ 538.11 ms │
    └──────────┴───────────┴───────────┴───────────┴───────────┴───────────┴──────────┴───────────┘
    ┌───────────┬────┬──────┬─────────┬─────────┬───────────┬──────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min │
    ├───────────┼────┼──────┼─────────┼─────────┼───────────┼──────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 137,554 │ 164,509 │ 133,707.5 │ 29121.54 │ 0   │
    └───────────┴────┴──────┴─────────┴─────────┴───────────┴──────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    8.38M notifications received in 64.22s (8,382,200 of 8,372,700 expected), 2629.1 MB read
    ```

## With every client connected

The same runs once more, with 3,662,564 clients connected and waiting : what a server which is full of WebSocket clients still does.

| | No client, or 10,000 | 3,662,564 clients connected |
|---|--:|--:|
| A notification for one person, 1,000 a second : delivery p50 | 0.94 ms | **1.28 ms** |
| … p99 | 6.54 ms | **121 ms** |
| A notification for one person, as many as the server takes | 21,208 / s | **8,384 / s** |
| Get all with both tokens, 100 connections (autocannon) | 9,529 req/s | **3,997 req/s** |
| … latency p50 / p99 | 10 ms / 21 ms | **14 ms / 289 ms** |

**Notification, 1,000 a second**

Calls / second (paced)

987

59,220 calls in 60 s, 10 connections

Notifications / second

970

59,225 received by 3,662,564 clients

Delivery p50

1.28ms

average 4.51 ms

Delivery p99

121ms

max 454 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **3.5 vCPU** · Redis **0.9 vCPU** · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU** · whole server busy **60 %** · load generator busy **8 %**

    autocannon · A notification for one person, 1,000 a second, every client connected

    ```text
    $ autocannon -c 10 -d 60 -R 1000 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    10 connections

    ┌─────────┬──────┬───────┬────────┬────────┬──────────┬──────────┬────────┐
    │ Stat    │ 2.5% │ 50%   │ 97.5%  │ 99%    │ Avg      │ Stdev    │ Max    │
    ├─────────┼──────┼───────┼────────┼────────┼──────────┼──────────┼────────┤
    │ Latency │ 1 ms │ 27 ms │ 248 ms │ 291 ms │ 63.77 ms │ 76.63 ms │ 454 ms │
    └─────────┴──────┴───────┴────────┴────────┴──────────┴──────────┴────────┘
    ┌───────────┬────────┬────────┬────────┬────────┬────────┬─────────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev   │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼─────────┼────────┤
    │ Req/Sec   │ 490    │ 708    │ 1,000  │ 1,010  │ 987    │ 74.78   │ 490    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼─────────┼────────┤
    │ Bytes/Sec │ 175 kB │ 253 kB │ 357 kB │ 361 kB │ 352 kB │ 26.7 kB │ 175 kB │
    └───────────┴────────┴────────┴────────┴────────┴────────┴─────────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 1            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 2            │
    ├────────────┼──────────────┤
    │ 50         │ 27           │
    ├────────────┼──────────────┤
    │ 75         │ 109          │
    ├────────────┼──────────────┤
    │ 90         │ 180          │
    ├────────────┼──────────────┤
    │ 97.5       │ 248          │
    ├────────────┼──────────────┤
    │ 99         │ 291          │
    ├────────────┼──────────────┤
    │ 99.9       │ 425          │
    ├────────────┼──────────────┤
    │ 99.99      │ 451          │
    ├────────────┼──────────────┤
    │ 99.999     │ 453          │
    └────────────┴──────────────┘

    60k requests in 60.03s, 21.1 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    3,662,564 clients subscribed, 64.05s

    ┌──────────┬─────────┬─────────┬──────────┬───────────┬─────────┬──────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%    │ 99%       │ Avg     │ Stdev    │ Max      │
    ├──────────┼─────────┼─────────┼──────────┼───────────┼─────────┼──────────┼──────────┤
    │ Delivery │ 0.79 ms │ 1.28 ms │ 24.11 ms │ 121.41 ms │ 4.51 ms │ 22.86 ms │ 454.4 ms │
    └──────────┴─────────┴─────────┴──────────┴───────────┴─────────┴──────────┴──────────┘
    ┌───────────┬────┬──────┬───────┬───────┬───────┬────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg   │ Stdev  │ Min │
    ├───────────┼────┼──────┼───────┼───────┼───────┼────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 1,000 │ 1,010 │ 939.1 │ 223.73 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴───────┴────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    59k notifications received in 64.05s (59,225 of 59,220 expected), 10.7 MB read
    ```

**Notification, as many as the server takes**

Calls / second

8,481

508,854 calls in 60 s, 100 connections

Notifications / second

8,384

508,954 received by 3,662,564 clients

Delivery p50

5.85ms

average 11.6 ms

Delivery p99

194ms

max 621 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **6.6 vCPU** · Redis **0.2 vCPU** · MongoDB **0.0 vCPU** · sandboxes **0.0 vCPU** · whole server busy **91 %** · load generator busy **17 %**

    autocannon · A notification for one person, as many as the server takes, every client connected

    ```text
    $ autocannon -c 100 -d 60 -w 10 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    100 connections
    10 workers

    ┌─────────┬──────┬──────┬───────┬────────┬──────────┬──────────┬────────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%    │ Avg      │ Stdev    │ Max    │
    ├─────────┼──────┼──────┼───────┼────────┼──────────┼──────────┼────────┤
    │ Latency │ 3 ms │ 5 ms │ 66 ms │ 195 ms │ 11.27 ms │ 32.11 ms │ 496 ms │
    └─────────┴──────┴──────┴───────┴────────┴──────────┴──────────┴────────┘
    ┌───────────┬────────┬─────────┬─────────┬─────────┬──────────┬──────────┬────────┐
    │ Stat      │ 1%     │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev    │ Min    │
    ├───────────┼────────┼─────────┼─────────┼─────────┼──────────┼──────────┼────────┤
    │ Req/Sec   │ 3,069  │ 4,643   │ 8,591   │ 10,215  │ 8,481.09 │ 1,234.13 │ 3,069  │
    ├───────────┼────────┼─────────┼─────────┼─────────┼──────────┼──────────┼────────┤
    │ Bytes/Sec │ 1.1 MB │ 1.66 MB │ 3.07 MB │ 3.65 MB │ 3.03 MB  │ 441 kB   │ 1.1 MB │
    └───────────┴────────┴─────────┴─────────┴─────────┴──────────┴──────────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 3            │
    ├────────────┼──────────────┤
    │ 2.5        │ 3            │
    ├────────────┼──────────────┤
    │ 10         │ 4            │
    ├────────────┼──────────────┤
    │ 25         │ 5            │
    ├────────────┼──────────────┤
    │ 50         │ 5            │
    ├────────────┼──────────────┤
    │ 75         │ 7            │
    ├────────────┼──────────────┤
    │ 90         │ 8            │
    ├────────────┼──────────────┤
    │ 97.5       │ 66           │
    ├────────────┼──────────────┤
    │ 99         │ 195          │
    ├────────────┼──────────────┤
    │ 99.9       │ 389          │
    ├────────────┼──────────────┤
    │ 99.99      │ 459          │
    ├────────────┼──────────────┤
    │ 99.999     │ 490          │
    └────────────┴──────────────┘

    509k requests in 60.01s, 182 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    3,662,564 clients subscribed, 63.71s

    ┌──────────┬─────────┬─────────┬──────────┬───────────┬──────────┬──────────┬───────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%    │ 99%       │ Avg      │ Stdev    │ Max       │
    ├──────────┼─────────┼─────────┼──────────┼───────────┼──────────┼──────────┼───────────┤
    │ Delivery │ 3.65 ms │ 5.85 ms │ 65.98 ms │ 194.43 ms │ 11.58 ms │ 31.99 ms │ 621.06 ms │
    └──────────┴─────────┴─────────┴──────────┴───────────┴──────────┴──────────┴───────────┘
    ┌───────────┬────┬──────┬───────┬────────┬─────────┬─────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5%  │ Avg     │ Stdev   │ Min │
    ├───────────┼────┼──────┼───────┼────────┼─────────┼─────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 8,416 │ 10,294 │ 8,130.0 │ 2005.53 │ 0   │
    └───────────┴────┴──────┴───────┴────────┴─────────┴─────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    509k notifications received in 63.71s (508,954 of 508,854 expected), 92.4 MB read
    ```

**Get all with both tokens**

Requests / second

3,997

239,825 requests in 60 s

Latency p50

14ms

average 24.52 ms

Latency p99

289ms

max 590 ms

Errors

0

non-2xx, errors, timeouts

(Server during this run) API Maker **5.3 vCPU** · Redis **0.0 vCPU** · MongoDB **1.4 vCPU** · sandboxes **0.0 vCPU** · whole server busy **94 %** · load generator busy **13 %**

    autocannon · get all with both tokens · 3,662,564 WebSocket clients connected

    ```text
    $ autocannon -c 100 -d 60 -w 10 -l -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" "http://<server>:38246/api/schema/bench/mongodb/am_bench/customers"
    Running 60s test @ http://<server>:38246/api/schema/bench/mongodb/am_bench/customers
    100 connections
    10 workers

    ┌─────────┬──────┬───────┬────────┬────────┬──────────┬──────────┬────────┐
    │ Stat    │ 2.5% │ 50%   │ 97.5%  │ 99%    │ Avg      │ Stdev    │ Max    │
    ├─────────┼──────┼───────┼────────┼────────┼──────────┼──────────┼────────┤
    │ Latency │ 6 ms │ 14 ms │ 188 ms │ 289 ms │ 24.52 ms │ 46.55 ms │ 590 ms │
    └─────────┴──────┴───────┴────────┴────────┴──────────┴──────────┴────────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min    │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┤
    │ Req/Sec   │ 2,049   │ 3,213   │ 4,051   │ 4,567   │ 3,997.44 │ 432.42  │ 2,049  │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┤
    │ Bytes/Sec │ 5.61 MB │ 8.79 MB │ 11.1 MB │ 12.5 MB │ 10.9 MB  │ 1.18 MB │ 5.6 MB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 3            │
    ├────────────┼──────────────┤
    │ 1          │ 5            │
    ├────────────┼──────────────┤
    │ 2.5        │ 6            │
    ├────────────┼──────────────┤
    │ 10         │ 8            │
    ├────────────┼──────────────┤
    │ 25         │ 11           │
    ├────────────┼──────────────┤
    │ 50         │ 14           │
    ├────────────┼──────────────┤
    │ 75         │ 18           │
    ├────────────┼──────────────┤
    │ 90         │ 31           │
    ├────────────┼──────────────┤
    │ 97.5       │ 188          │
    ├────────────┼──────────────┤
    │ 99         │ 289          │
    ├────────────┼──────────────┤
    │ 99.9       │ 427          │
    ├────────────┼──────────────┤
    │ 99.99      │ 507          │
    ├────────────┼──────────────┤
    │ 99.999     │ 573          │
    └────────────┴──────────────┘

    240k requests in 60.02s, 656 MB read
    ```

## Questions

### How many WebSocket connections can API Maker hold on 8 shared vCPUs and 32 GB ?

3,662,564 clients were connected at the same time on this server, each with both tokens and a subscription of its own, with MongoDB, Redis and two sandboxes on the same machine. Memory is what ends first : a client costs about 8.8 KB of the server in all.

### How much memory does a WebSocket client cost ?

About 8.8 KB : 3.2 KB in the API Maker process, 4.5 KB in the Linux kernel (its socket) and 1.1 KB in Redis (its subscription). Measured between 1,000,000 and 3,000,000 clients which wait, each connected with both tokens and one subscription.

### How many clients can connect each second ?

10,939 clients a second connected with both tokens, subscribed and left, 100 at a time ; 24,719 a second without a subscription. With a can user connect code on the event : 9,280 a second.

### How fast does a notification reach a client ?

At 1,000 notifications a second, each for one person among 10,000 : 0.94 ms from the HTTP call to the client (p50), 6.54 ms for 99 % of them. With as many calls as the server takes : 21,208 notifications a second.

### Do connected WebSocket clients slow the APIs down ?

Get all with both tokens answered 9,529 requests a second with no WebSocket client, and 3,997 with 3,662,564 clients connected and waiting. A client which waits costs memory ; its CPU is a ping a minute.
