Part 9 · 2 chapters · ~12 min
The Lab
Seven deliberate pathologies in one zero-dependency service (a memory leak, a blocked event loop, N+1 queries, pool exhaustion, threadpool starvation, GC pressure and lock contention), the numbers measured on this machine, and a worksheet for diagnosing each with the course's tools.
16
Run it and break it
code
node --inspect modules/bdiag/lab/server.mjs # http://localhost:8930, inspector on 9229 curl localhost:8930/stats # pool, RSS, heap, event loop delay p99 curl localhost:8930/fixes # the answer key (try first, read later) routes: /leak /block /n1 /pool-leak /hash /dns /gc /contention /healthz /stats /fixes
THE LAB, MEASURED
numbers from running modules/bdiag/lab/server.mjs on this machine
swipe the figure sideways, or tap expand for full screen
1/5
baseline
A health check returns in about 4 ms: the process and the network are fine.
healthy baseline: 4 mscurl -w %{time_total}
17
Worksheet
| route | symptom to reproduce | tool to use | evidence you should see |
|---|---|---|---|
| /leak | RSS grows 1 MB per call | three heap snapshots (Node part 1) | Buffers retained by a module-level array |
| /block | all routes slow while it runs | --cpu-prof, ELU, event loop delay | a wide frame in the route handler |
| /n1 | 1 s responses with idle CPU | traces (or log query counts) | 51 sequential query spans |
| /pool-leak | after errors, everything hangs | /stats pool metrics, a heap snapshot of waiters | inUse = size, waiting grows |
| /hash then /dns | unrelated route slow | timing of dns.lookup, UV_THREADPOOL_SIZE experiment | lookup time drops with a bigger pool |
| /gc | CPU high, many short pauses | --trace-gc | frequent scavenges per request |
| /contention | latency rises with concurrency, CPU flat | load test at increasing concurrency | p99 ≈ 50 ms × queue depth |