Slides and code
at
Slides and code
at
Independent Node.js consultant and educator
I help developers level up with Node.js at simonplend.com/blog
Author of Express API Validation Essentials
expressapivalidation.com
π¦ Problems at Ice Cream Corp
π¦ Performance testing
π¦ Menu Service v2β¦ ?
π¦ The Abort API
π¦ Menu Service v3
π¦ Abort API support in Node.js
Photo by Markus Spiske on Unsplash
Photo by Pawel Janiak on Unsplash
import Fastify from "fastify";
const app = Fastify();
app.get("/stock", function (request, reply) {
const stock = [
{ id: "cf93d53f-7f60-4c9d-a543-ef217a09269b", name: "Cookies 'n' Cream", stock: 8532 },
{ id: "41373bb6-e6fb-4606-8f01-1cd24e228939", name: "Neopolitan", stock: 0 },
{ id: "8e884a8d-ae04-4518-80b7-377ee5bcecc6", name: "Pistachio", stock: 6437 }
];
const delay = Math.floor(Math.random() * 10000);
setTimeout(() => {
reply.send({ stock, delay });
}, delay);
});
await app.listen(4000);
import fetch from "node-fetch";
import Fastify from "fastify";
async function makeRequest(url) {
const response = await fetch(url);
const responseData = await response.json();
return responseData;
}
const app = Fastify();
app.get("/menu", async function (request, reply) {
const stockServiceEndpoint = "http://stock-service.icecreamcorp.net:4000/stock";
const stockServiceResponse = await makeRequest(stockServiceEndpoint);
reply.send({ stockServiceResponse });
});
await app.listen(3000);
Running 60s test @ http://menu-service.icecreamcorp.net:3000/menu
100 connections
βββββββββββ¬βββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββββββ¬βββββββββββββ¬βββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg * β Stdev β Max β
βββββββββββΌβββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββ€
β Latency β 244 ms β 4862 ms β 9718 ms β 9900 ms β 4898.42 ms β 2941.22 ms β 10000 ms β
βββββββββββ΄βββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββββββ΄βββββββββββββ΄βββββββββββ
βββββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg * β Stdev β Min β
βββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Req/Sec β 6 β 8 β 19 β 27 β 19.15 β 4.63 β 6 β
βββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ
Req/Bytes counts sampled once per second.
1k requests in 60.03s, 539 kB read
3 errors (3 timeouts)
Running 60s test @ http://menu-service.icecreamcorp.net:3000/menu
100 connections
βββββββββββ¬βββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββββ¬ββββββββββββ¬ββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg * β Stdev β Max β
βββββββββββΌβββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββββΌββββββββββββΌββββββββββ€
β Latency β 253 ms β 1004 ms β 1024 ms β 1146 ms β 957.63 ms β 176.57 ms β 1217 ms β
βββββββββββ΄βββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββββ΄ββββββββββββ΄ββββββββββ
βββββββββββββ¬ββββββββββ¬ββββββββ¬ββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββ¬ββββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg * β Stdev β Min β
βββββββββββββΌββββββββββΌββββββββΌββββββββΌββββββββββΌββββββββββΌβββββββββΌββββββββββ€
β Req/Sec β 13 β 100 β 105 β 112 β 103.47 β 12.1 β 13 β
βββββββββββββ΄ββββββββββ΄ββββββββ΄ββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββ΄ββββββββββ
Req/Bytes counts sampled once per second.
612 2xx responses, 5596 non 2xx responses
6k requests in 60.03s, 1.97 MB read
A JavaScript API which consists of two classes:
AbortController
and AbortSignal
const controller = new AbortController();
const signal = controller.signal;
signal.addEventListener("abort", () => {
console.log("The abort signal was triggered");
}, { once: true });
controller.abort();
The Abort API originated in the Web Platform
Microsoft Edge 16 was the first browser to implement the Abort API in October 2017.
Now all major browsers support it.
Source: caniuse.com
Stable support in Node.js since v15.4.0, released in December 2020.
Photo by David Becker on Unsplash
AbortSignal
import fetch from "node-fetch";
const cancelRequest = new AbortController();
fetch("https://jsonplaceholder.typicode.com/posts", {
signal: cancelRequest.signal
})
.then(response => response.json())
.then(responseData => console.log(responseData))
.catch(error => console.error(error));
cancelRequest.abort();
$ node node-fetch-with-abortsignal.js
file:///dev/node_modules/node-fetch/src/index.js:56
const error = new AbortError('The operation was aborted.');
^
AbortError: The operation was aborted.
at abort (file:///dev/node_modules/node-fetch/src/index.js:56:18)
at EventTarget.abortAndFinalize (file:///dev/node_modules/node-fetch/src/index.js:75:4)
at EventTarget.[nodejs.internal.kHybridDispatch] (node:internal/event_target:562:20)
at EventTarget.dispatchEvent (node:internal/event_target:504:26)
at abortSignal (node:internal/abort_controller:97:10)
at AbortController.abort (node:internal/abort_controller:122:5)
at file:///dev/abort-api/node-fetch-with-abortsignal.js:12:16
at ModuleJob.run (node:internal/modules/esm/module_job:183:25)
at async Loader.import (node:internal/modules/esm/loader:178:24)
at async Object.loadESM (node:internal/process/esm_loader:68:5) {
type: 'aborted'
}
Running 60s test @ http://menu-service.icecreamcorp.net:3000/menu
100 connections
βββββββββββ¬βββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββββ¬ββββββββββββ¬ββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg * β Stdev β Max β
βββββββββββΌβββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββββΌββββββββββββΌββββββββββ€
β Latency β 282 ms β 1006 ms β 1116 ms β 1167 ms β 967.9 ms β 172.98 ms β 1251 ms β
βββββββββββ΄βββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββββ΄ββββββββββββ΄ββββββββββ
βββββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg * β Stdev β Min β
βββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Req/Sec β 4 β 78 β 104 β 111 β 102.57 β 13.55 β 4 β
βββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ
Req/Bytes counts sampled once per second.
614 2xx responses, 5540 non 2xx responses
6k requests in 60.03s, 1.94 MB read
v16.x | >= v14.17.0 | Older versions | |
---|---|---|---|
AbortController +AbortSignal classes | β | Experimental | Use abort-controller package |
Node.js core APIs which accept AbortSignal | β | β | β |
Enable abort classes with flag e.g. node --experimental-abortcontroller server.js
OR npm install abort-controller
and:
import AbortController from "abort-controller";
AbortSignal
in Node.js core API methodschild_process.exec
child_process.execFile
child_process.fork
child_process.spawn
dgram.createSocket
events.on
events.once
fs.readFile
fs.watch
fs.writeFile
http.request
https.request
http2Session.request
timers/promises.setImmediate
timers/promises.setTimeout
readline.Interface
readline.createInterface
AbortSignal
Promise.race()
setTimeout patternAbortSignal
: