1.Locating the time in a slow request
Start by splitting one number into four. A request takes 2,400 ms; how much of that was the database, how much was waiting on other services, how much was your own Python, and how much happened before your view was even called? Middleware is the part people forget: every entry in `MIDDLEWARE` runs on every request, in order, on the way in and on the way out — so one middleware doing a database lookup per request adds its cost to every endpoint, including the health check. Until the 2,400 is broken up, any fix is a guess.
Key features
- Every middleware runs on every request, both inbound and outbound — its cost lands on all endpoints, including health checks
- Middleware ordering is a dependency graph, not a preference; reordering to "put the cheap one first" can break authentication or CSRF
- Session and authentication middleware issue queries before your view runs, so "3 queries in the view" is rarely the request total
- Split total into `db_ms`, `external_ms`, `cpu_ms` and middleware time before opening any file
- A p95 does not tell you the shape — look at the distribution, or you cannot tell "uniformly slow" from "a bad tail"
- Attach the numbers to individual slow requests; aggregates cannot be drilled into after the fact
Reading the four numbers
- 0 ms: Request accepted by the worker — anything before this is server queueing, not your code
- 0–40 ms: Middleware, inbound — session read + user lookup + feature flags = 3 queries before the view
- 40–2,250 ms: The view — db 2,210 ms across 431 queries — the count says N+1, not a slow query
- 2,250–2,380 ms: Serialization — invisible in the SQL log; shows up as cpu_ms
- 2,380–2,400 ms: Middleware, outbound — compression, headers — runs on every response too
- after: What a single duration told you — nothing: the same 2,400 ms could have been any one of these spans
Command
MIDDLEWARE = [...] # every entry runs on EVERY request, in and out
# cost here is multiplied by your total request rate, not by the endpoint'sRefuse to open a file until one duration is four numbers: database, external, CPU and — the one people forget — middleware. Every entry in `MIDDLEWARE` runs on every request in both directions, so a query in there is the most expensive query in the codebase; the tell is a floor under every endpoint, including ones that do nothing. And always read p50 next to p95 and p99, because uniform slowness and a bad tail look identical in a single percentile and need opposite investigations.