Skip to content

Commit 1c57cea

Browse files
committed
chore: progressing with chapter 12
1 parent 19bcd4a commit 1c57cea

File tree

9 files changed

+2166
-0
lines changed

9 files changed

+2166
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# 04-http-cluster-zero-downtime
2+
3+
This example demonstrates how to benchmark a simple HTTP server that uses the
4+
cluster module and provides auto restarting of failed workers.
5+
6+
## Dependencies
7+
8+
This example requires you to install some third-party dependencies from npm.
9+
10+
If you have `pnpm` installed, you can do that with:
11+
12+
```bash
13+
pnpm install
14+
```
15+
16+
Alternatively, if you prefer to use another package manager, make sure to delete
17+
the `pnpm-lock.yaml` file before using it.
18+
19+
If you want to use `npm`, you can run:
20+
21+
```bash
22+
npm install
23+
```
24+
25+
If you want to use `yarn`, you can run:
26+
27+
```bash
28+
yarn install
29+
```
30+
31+
## Run
32+
33+
To run the example server:
34+
35+
```bash
36+
npm start # or `node app.js`
37+
```
38+
39+
To run a benchmark (in another terminal):
40+
41+
```bash
42+
npm run benchmark # or `npx autocannon http://localhost:8080`
43+
```
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import cluster from 'node:cluster'
2+
import { once } from 'node:events'
3+
import { createServer } from 'node:http'
4+
import { cpus } from 'node:os'
5+
6+
if (cluster.isPrimary) {
7+
const availableCpus = cpus()
8+
console.log(`Clustering to ${availableCpus.length} processes`)
9+
for (const _ of availableCpus) {
10+
cluster.fork()
11+
}
12+
cluster.on('exit', (worker, code) => {
13+
if (code !== 0 && !worker.exitedAfterDisconnect) {
14+
console.log(`Worker ${worker.process.pid} crashed. Starting a new worker`)
15+
cluster.fork()
16+
}
17+
})
18+
process.on('SIGUSR2', async () => {
19+
const workers = Object.values(cluster.workers)
20+
for (const worker of workers) {
21+
console.log(`Stopping worker: ${worker.process.pid}`)
22+
worker.disconnect()
23+
await once(worker, 'exit')
24+
if (!worker.exitedAfterDisconnect) {
25+
continue
26+
}
27+
const newWorker = cluster.fork()
28+
await once(newWorker, 'listening')
29+
}
30+
})
31+
} else {
32+
const server = createServer((_req, res) => {
33+
// simulates CPU intensive work
34+
let i = 1e7
35+
while (i > 0) {
36+
i--
37+
}
38+
39+
console.log(`Handling request from ${process.pid}`)
40+
res.end(`Hello from ${process.pid}\n`)
41+
})
42+
43+
server.listen(8080, () => console.log(`Started at ${process.pid}`))
44+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "04-http-cluster-zero-downtime",
3+
"version": "1.0.0",
4+
"description": "This example demonstrates how to benchmark a simple HTTP server that uses the cluster module and provides auto restarting of failed workers",
5+
"type": "module",
6+
"scripts": {
7+
"start": "node app.js",
8+
"benchmark": "autocannon http://localhost:8080"
9+
},
10+
"engines": {
11+
"node": ">=24"
12+
},
13+
"engineStrict": true,
14+
"keywords": [],
15+
"author": "Luciano Mammino and Mario Casciaro",
16+
"license": "MIT",
17+
"devDependencies": {
18+
"autocannon": "^8.0.0"
19+
}
20+
}

0 commit comments

Comments
 (0)