Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions frameworks/fulmine-uwslite/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM node:26-trixie-slim AS build
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates git && \
rm -rf /var/lib/apt/lists/*
RUN git config --global url."https://github.com/".insteadOf "ssh://git@github.com/"
WORKDIR /app
COPY package.json .
RUN npm install --omit=dev

FROM node:26-trixie-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY app.js .
ENV NODE_ENV=production
EXPOSE 8080
CMD ["node", "app.js"]
17 changes: 17 additions & 0 deletions frameworks/fulmine-uwslite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# fulmine.js - uwsLite

fulmine.js with its routes written with `app.uwsLite`: `(req, res)` handlers that uWebSockets.js serves over two small objects, with no Express layer in front. It runs only the H/1.1 profiles that count for the score.

## Stack

- **Language:** JavaScript
- **Runtime:** Node.js 26
- **Framework:** [fulmine.js](https://github.com/nigrosimone/fulmine.js)
- **Build:** multi-stage, `node:26-trixie-slim` for both stages

## Endpoints

- `GET` and `POST /baseline11`: the sum of the query, and of the body
- `GET /delay/:ms`: answers after the wait
- `GET /json/:count?m=`: the dataset, compressed with brotli when asked
- `GET /json/:count` and `POST /echo` over TLS on 8081
73 changes: 73 additions & 0 deletions frameworks/fulmine-uwslite/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// fulmine.js with app.uwsLite: an (req, res) route that uWS serves over two small objects.
// https://fulmine.sndesign.it/uws-routes#lite-routes-app-uwslite
const fs = require('fs');
const zlib = require('zlib');
const express = require('fulmine.js');

// One worker per usable core (cgroup quota first), all on the same port with SO_REUSEPORT.
// https://fulmine.sndesign.it/examples/cluster
const app = express({ cluster: 'auto' });

const dataset = JSON.parse(fs.readFileSync('/data/dataset.json', 'utf8'));

// Brotli quality 3, as the fulmine entry.
const compress = {
encodings: ['br'],
brotli: { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 3 } },
};

function sumQuery(query) {
let sum = 0;
for (const k in query) {
const n = parseInt(query[k], 10);
if (n === n) sum += n;
}
return sum;
}

app.uwsLite.get('/baseline11', (req, res) => {
res.type('text/plain').send(String(sumQuery(req.query)));
});

app.uwsLite.post('/baseline11', { body: 'text' }, (req, res) => {
let total = sumQuery(req.query);
const n = parseInt(req.body.trim(), 10);
if (n === n) total += n;
res.type('text/plain').send(String(total));
});

app.uwsLite.get('/delay/:ms', (req, res) => {
const ms = parseInt(req.params.ms, 10) || 0;
setTimeout(() => res.type('text/plain').send(String(ms)), ms);
});

const json = (req, res) => {
const count = Math.min(Math.max(parseInt(req.params.count, 10) || 0, 0), dataset.length);
const m = parseInt(req.query.m, 10) || 1;
const items = new Array(count);
for (let i = 0; i < count; i++) {
const d = dataset[i];
items[i] = {
id: d.id, name: d.name, category: d.category,
price: d.price, quantity: d.quantity, active: d.active,
tags: d.tags, rating: d.rating,
total: d.price * d.quantity * m
};
}
res.json({ items, count });
};

app.uwsLite.get('/json/:count', { compress }, json);

// json-tls and 8gbit over TLS on 8081, when the harness mounts the certs. json-tls never sends
// Accept-Encoding, so this route has no compress. The echo answers while the body is lent.
if (fs.existsSync('/certs/server.key') && fs.existsSync('/certs/server.crt')) {
const tls = express({ uwsOptions: { key_file_name: '/certs/server.key', cert_file_name: '/certs/server.crt' } });
tls.uwsLite.get('/json/:count', json);
tls.uwsLite.post('/echo', { body: 'lent', limit: '1mb' }, (req, res) => {
res.type('application/octet-stream').send(req.body);
});
tls.listen(8081);
}

app.listen(8080);
28 changes: 28 additions & 0 deletions frameworks/fulmine-uwslite/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"display_name": "fulmine.js - uwsLite",
"language": "JS",
"type": "emerging",
"mode": "standard",
"completeness": {
"routing": true,
"middleware": true,
"request": true,
"response": true
},
"engine": "uwebsockets",
"description": "fulmine.js routes written with app.uwsLite: (req, res) handlers on uWebSockets.js over two small objects, with route middleware and streams.",
"repo": "https://github.com/nigrosimone/fulmine.js",
"website": "https://fulmine.sndesign.it/",
"enabled": true,
"tests": [
"baseline",
"limited-conn",
"async",
"latency-10k",
"latency-1m",
"json-comp",
"json-tls",
"8gbit"
],
"maintainers": ["nigrosimone"]
}
7 changes: 7 additions & 0 deletions frameworks/fulmine-uwslite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "httparena-fulmine-uwslite",
"private": true,
"dependencies": {
"fulmine.js": "^5.31.0"
}
}
15 changes: 15 additions & 0 deletions site/data/frameworks.json
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,21 @@
"response": false
}
},
"fulmine.js - uwsLite": {
"dir": "fulmine-uwslite",
"description": "fulmine.js routes written with app.uwsLite: (req, res) handlers on uWebSockets.js over two small objects, with route middleware and streams.",
"repo": "https://github.com/nigrosimone/fulmine.js",
"type": "emerging",
"engine": "uwebsockets",
"mode": "standard",
"website": "https://fulmine.sndesign.it/",
"completeness": {
"routing": true,
"middleware": true,
"request": true,
"response": true
}
},
"fulmine.js": {
"dir": "fulmine",
"description": "fulmine.js (drop-in Express 5 on uWebSockets.js) with its own cluster option for multi-core scaling.",
Expand Down
197 changes: 197 additions & 0 deletions site/data/results/fulmine.js---uwslite.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
{
"framework": "fulmine.js - uwsLite",
"results": {
"8gbit-512": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 49342,
"avg_latency": "92.2us",
"p99_latency": "120.0us",
"cpu": "216.5%",
"memory": "1.2GiB",
"connections": 512,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "511.13MB/s",
"input_bw": "481.86MB/s",
"reconnects": 0,
"status_2xx": 246774,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0,
"cpu_usec": 11950026,
"cpu_per_req_us": 48.425,
"target_rate": 50000,
"rate_ratio": 0.9868,
"p99_9_latency": "3539.0us"
},
"async-32000": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 2458459,
"avg_latency": "12.92ms",
"p99_latency": "16.10ms",
"cpu": "5802.7%",
"memory": "3.5GiB",
"connections": 32000,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "276.61MB/s",
"input_bw": "112.54MB/s",
"reconnects": 0,
"status_2xx": 24584597,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0
},
"baseline-4096": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 2711810,
"avg_latency": "1.51ms",
"p99_latency": "2.90ms",
"cpu": "6681.9%",
"memory": "1.7GiB",
"connections": 4096,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "305.07MB/s",
"input_bw": "209.48MB/s",
"reconnects": 0,
"status_2xx": 13559054,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0
},
"json-comp-16384": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 476174,
"avg_latency": "34.09ms",
"p99_latency": "79.80ms",
"cpu": "6244.9%",
"memory": "2.3GiB",
"connections": 16384,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "635.10MB/s",
"input_bw": "35.42MB/s",
"reconnects": 87069,
"status_2xx": 2380870,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0
},
"json-comp-4096": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 478865,
"avg_latency": "8.54ms",
"p99_latency": "24.30ms",
"cpu": "6318.8%",
"memory": "2.1GiB",
"connections": 4096,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "638.69MB/s",
"input_bw": "35.62MB/s",
"reconnects": 94151,
"status_2xx": 2394325,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0
},
"json-tls-4096": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 1388473,
"avg_latency": "2.92ms",
"p99_latency": "58.69ms",
"cpu": "6392.9%",
"memory": "1.7GiB",
"connections": 4096,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "4.71GB",
"reconnects": 0,
"status_2xx": 7080611,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0
},
"latency-10k-1024": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 9983,
"avg_latency": "74.3us",
"p99_latency": "108.0us",
"cpu": "30.7%",
"memory": "1.3GiB",
"connections": 1024,
"threads": 64,
"duration": "20s",
"pipeline": 1,
"bandwidth": "1.17MB/s",
"reconnects": 0,
"status_2xx": 199679,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0,
"cpu_usec": 6391614,
"cpu_per_req_us": 32.0094,
"target_rate": 10000,
"rate_ratio": 0.9983,
"p99_9_latency": "186.0us"
},
"latency-1m-1024": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 998128,
"avg_latency": "109.8us",
"p99_latency": "197.0us",
"cpu": "2918.9%",
"memory": "1.5GiB",
"connections": 1024,
"threads": 64,
"duration": "20s",
"pipeline": 1,
"bandwidth": "116.78MB/s",
"reconnects": 0,
"status_2xx": 19966012,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0,
"cpu_usec": 529359256,
"cpu_per_req_us": 26.513,
"target_rate": 1000000,
"rate_ratio": 0.9981,
"p99_9_latency": "4186.0us"
},
"limited-conn-4096": {
"framework": "fulmine.js - uwsLite",
"language": "JS",
"rps": 2318031,
"avg_latency": "1.74ms",
"p99_latency": "6.44ms",
"cpu": "6463.1%",
"memory": "1.6GiB",
"connections": 4096,
"threads": 64,
"duration": "5s",
"pipeline": 1,
"bandwidth": "260.76MB/s",
"input_bw": "179.06MB/s",
"reconnects": 1158239,
"status_2xx": 11590156,
"status_3xx": 0,
"status_4xx": 0,
"status_5xx": 0
}
}
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.